//
// Created by xkj on 2020/8/17.
//
#ifndef PROJ_ANDROID_HANDTIANSCENE_H
#define PROJ_ANDROID_HANDTIANSCENE_H

#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <algorithm>

#include <map>
#include <string>
#include <atomic>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <functional>
#include <cmath>
#include <thread>
#include <regex>
#include <mutex>
#include <atomic>

#include "base/CCScheduler.h"
#include "extensions/cocos-ext.h"
#include "network/SocketIO.h"
#include "base/ccUTF8.h"
#include "ui/UIHelper.h"

#include "HelloWorldScene.h"
#include "base/CCDirector.h"

#include "renderer/CCRenderer.h"
#include "renderer/CCCustomCommand.h"
#include "network/CCDownloader.h"

#include "json/rapidjson.h"
#include "json/document-wrapper.h"
#include "json/stringbuffer.h"
#include "json/writer.h"
#include "network/HttpClient.h"

#include "BlueToothHelper.h"
#include "RemoteControlHelper.h"
#include "WordMappingTian.h"
#include "OneWordDetail.h"
#include "HttpUtils.h"
#include "TianHelper.h"
#include "SIOCommentList.h"

#include "../cocos2d/cocos/editor-support/cocostudio/SimpleAudioEngine.h"
#include "audio/include/AudioEngine.h"

#include "../cocos2d/cocos/platform/CCPlatformMacros.h"

#include "physics/CCPhysicsBody.h"
#include "physics/CCPhysicsShape.h"
#include "physics/CCPhysicsJoint.h"
#include "physics/CCPhysicsWorld.h"
#include "physics/CCPhysicsHelper.h"

#include "SocketIOHelper.h"
#include "network/WebSocket.h"

//#include "ClassPathChoose.h"

//#define  LOG_TAG    "bttt-c++"
//#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

USING_NS_CC;
USING_NS_CC_EXT;

using namespace std;
using namespace cocos2d::network;
using namespace CocosDenshion;
using namespace cocos2d::ui;

typedef std::array<DrawNode *,3> DrawNodeArr;
typedef std::array<Label *,8> LabelNodeArr;
typedef std::array<DrawNode *,8> HandDrawNodeArr;
typedef std::array<int, 3> DrawNodeArrCourse;
typedef  std::vector<std::vector<bool>> WordDetailDrawCourseCache;

#define  ASSERT_AND_ASSIGN(ox,oy,drawWidth,drawHeight,oneWordCache) \
if(ox >= 0 &&oy >= 0 &&ox < drawWidth &&oy < drawHeight){oneWordCache[oy][ox] = true;}

#define CLEAR_CANVAS_AND_SCORE(oneCanvasNode) oneCanvasNode->clear();static_cast<cocos2d::Label*>(oneCanvasNode->getChildByName("score-lab"))->setString("");

#define CLASS_DATA_INFO_PATH "CLASS_PATH_CHOOSE.plist"

typedef enum {
    NO_CHOOSE,
    CLASS_CHOOSE,
    CLASS_PAGELIST_CHOOSE,
    CLASS_PAGE_CHOOSE,
    CHANGE_PAGE
} CHOOSE_CLASS_PAGE;

class  HandTianScene: public cocos2d::Scene,public BlueToothHelperDelegate,public SocketIOHelperDelegate,public cocos2d::extension::TableViewDataSource, public cocos2d::extension::TableViewDelegate{
public:
    static cocos2d::Scene* createScene(){
        auto scene = HandTianScene::createWithPhysics();
        //scene->getPhysicsWorld()->setDebugDrawMask( PhysicsWorld::DEBUGDRAW_ALL);
        scene->addChild(HandTianScene::create());

        return scene;
    }

    static int classNum;
    static int pageNo;
    static int termNo;

    /*字帖指示区*/
    std::unique_ptr<network::Downloader> downloader;

    cocos2d::Label*  displayLabel = nullptr;
    cocos2d::Label* connectBleLabel;
    cocos2d::Size visibleSize;

    //下载器
    std::map<std::string, std::vector<char>> pageInfoSet;
    cocos2d::network::HttpRequest* hRequest;

    float stepTB;

    //muTianScale
    float muTianScale = 0.72;

    virtual bool init() override
    {
        if (!Scene::init()) {
            return false;
        }

        return true;
    }

    void initBg() {
        Vec2 origin = Director::getInstance()->getVisibleOrigin();

        //贴图的纹理图片宽高必须是2的n次幂，128x128
        auto bg = Sprite::create("background3.png");//, Rect(0, 0, visibleSize.width, visibleSize.height));
        Size mysize = bg->getContentSize();
        bg->setScaleX(visibleSize.width/mysize.width);
        bg->setScaleY(visibleSize.height/mysize.height);

        //贴图的纹理参数，水平重复平铺，垂直重复平铺
        /*
        Texture2D::TexParams tp = {                backend::SamplerFilter::LINEAR,
                                                   backend::SamplerFilter::LINEAR,
                                                   backend::SamplerAddressMode::REPEAT,
                                                   backend::SamplerAddressMode::REPEAT
        };
        //bg->getTexture()->setTexParameters(tp);
         */
        bg->setAnchorPoint(Vec2::ZERO);
        bg->setPosition(0,0);//origin + Vec2(visibleSize.width/2, visibleSize.height/2));
        this->addChild(bg, -1);

        reddiggTexture = Director::getInstance()->getTextureCache()->addImage("reddigg_effect.png");

        auto label = Label::createWithSystemFont(StringUtils::format("编译日期:%s %s",__DATE__,__TIME__), "fonts/content.ttf", 12.0);
        label->setColor(cocos2d::Color3B::WHITE);//名字颜色：00 D1 F1
        label->setAnchorPoint(Vec2(1,0));
        label->setPosition(visibleSize.width,0);
        this->addChild(label);

    }

    virtual void onEnterTransitionDidFinish() override {
        connectBleLabel = nullptr;
        displayLabel = nullptr;

        visibleSize = Director::getInstance()->getVisibleSize();
        initKeyBoard();

        initBg();

        initTitle();
        initPromptLayer();

        BlueToothHelper::notifyTarget = static_cast<BlueToothHelperDelegate*>(this);

        initStorePageInfo();
        initTian();

        //initTestJson();

        SocketIOHelper::delegate =  static_cast<SocketIOHelperDelegate *>(this);
        initSocketIO();

    }

    int tableNumPage = 17;
    void initTableView()
    {
        //tableNumPage;

        auto tianLayer = static_cast<LayerColor*>(this->getChildByName("tianLayer"));
        if(tianLayer == nullptr){
            return;
        }
        float oneTableRowHeight = (tianLayer->getContentSize().height/(tableNumPage+1));

        commentTVSize.x = tianLayer->getContentSize().width + 20;
        commentTVSize.y = oneTableRowHeight*tableNumPage;

        tableLayerWidth = (visibleSize.width - tianLayer->getContentSize().width)/2 - 40;

        auto colorLayer = LayerColor::create(Color4B(150,220,150,0), tableLayerWidth, commentTVSize.y);
        colorLayer->setAnchorPoint(Vec2(1,0));
        colorLayer->setName("comment_layer");
        colorLayer->setPosition(Vec2(commentTVSize.x,0));
        tianLayer->addChild(colorLayer);

        //commentTV
        Size winSize = Director::getInstance()->getWinSize();

        commentTV = TableView::create(this, colorLayer->getContentSize());
        commentTV->setDirection(ScrollView::Direction::VERTICAL);
        commentTV->setPosition(Vec2::ZERO);
        commentTV->setDelegate(this);
        commentTV->setVerticalFillOrder(TableView::VerticalFillOrder::TOP_DOWN);
        tianLayer->addChild(commentTV);

        commentTV->reloadData();

        float speed = (commentTVSize.y/tableNumPage)*tableNumPage;
        commentTV->setContentOffset(commentTV->getContentOffset() - Vec2(0, speed),false);
    }


    void scrollCommentTv(int time=1){
        float speed = (commentTVSize.y/tableNumPage)*time;
        commentTV->setContentOffset(commentTV->getContentOffset() + Vec2(0, speed), true);

        return;
    }

    virtual void scrollViewDidScroll(cocos2d::extension::ScrollView* view)override {

    }
    virtual void scrollViewDidZoom(cocos2d::extension::ScrollView* view)override {

    }
    virtual void tableCellTouched(cocos2d::extension::TableView* table, cocos2d::extension::TableViewCell* cell)override{

    }
    virtual cocos2d::Size tableCellSizeForIndex(cocos2d::extension::TableView *table, ssize_t idx)override{

        return Size(0, commentTVSize.y/tableNumPage+1);
    }
    virtual cocos2d::extension::TableViewCell* tableCellAtIndex(cocos2d::extension::TableView *table, ssize_t idx)override{
        TableViewCell *cell = table->dequeueCell();
        size_t ssss = oneSioStatInfo.commentListVec.size();

        if (!cell) {
            cell = new (std::nothrow) TableViewCell();
            cell->autorelease();

            fillCeilByEmptyCeil(cell);
        }else{
            if(ssss > idx){
                updateCeilByCommentList(cell, idx);
            }
        }

        return cell;
    }

    void updateCeilByCommentList(TableViewCell *cell,ssize_t idx)
    {
        //cell->getChildByName("cliping_layer")->setTag(oneSioStatInfo.commentListVec[idx].msg.id);
        cell->getChildByName("cliping_layer")->setVisible(true);

        ClippingNode* clipNode = (ClippingNode*)cell->getChildByName("cliping_layer");
        LayerColor* classPageLayer = (LayerColor*)clipNode->getChildByName("one_row_layer");
        Sprite*  mask = (Sprite*)clipNode->getStencil();

        auto nameLab = (Label*)classPageLayer->getChildByName("name");
        nameLab->setString(StringUtils::format("【%s】",oneSioStatInfo.commentListVec[idx].userInfo.nickname.c_str()));

        auto iconSprite = (Sprite*)classPageLayer->getChildByName("icon");
        //iconSprite->setPosition(Vec2(nameLab->getContentSize().width/2+33, cellHeight));

        auto labelMsgBody = (Label*)classPageLayer->getChildByName("msg_body");
        labelMsgBody->setString(oneSioStatInfo.commentListVec[idx].msg.msgBody.c_str());
        labelMsgBody->setPositionX(nameLab->getPosition().x + nameLab->getBoundingBox().size.width+10);// , cellHeight*0.68));
        //classPageLayer->setContentSize(Size(400+33, cellHeight));
        //labelMsgBody->getPosition().x+labelMsgBody->getContentSize().width

        float scaleXmask = labelMsgBody->getPosition().x+labelMsgBody->getContentSize().width+20;
        if(scaleXmask > tableLayerWidth){
            scaleXmask = tableLayerWidth;
        }

        mask->setScaleX(scaleXmask/mask->getContentSize().width);
        //playingSong("bobo.mp3");

        //mask->setScaleY(labelMsgBody->getContentSize().height/mask->getContentSize().height);

        //clipNode->setContentSize(Size(400+33, cellHeight));
        //labelMsgBody->getPosition().x+labelMsgBody->getContentSize().width
    }

    void fillCeilByEmptyCeil(TableViewCell *cell){
        float cellHeight = (commentTVSize.y/tableNumPage)*0.8;
        float cellPadding = (commentTVSize.y/tableNumPage)*0.2;

        LayerColor* classPageLayer = LayerGradient::create(Color4B(16,119,254,250),Color4B(103,166,255,250),Vec2(1,0));
        classPageLayer->setName("one_row_layer");
        classPageLayer->setAnchorPoint(Vec2(0, 0));//左下角
        classPageLayer->setPosition(Vec2(0,0));

        int headNum = cocos2d::random(1,5);
        std::string gender = "male";

        auto oneSprite = Sprite::create(StringUtils::format("%s-icon%d.png",gender.c_str(),headNum));
        oneSprite->setAnchorPoint(Vec2(0, 0.5));//左下角
        oneSprite->setScale((cellHeight*1.1)/oneSprite->getContentSize().height);
        oneSprite->setPosition(Vec2(10, cellHeight/2));
        oneSprite->setName("icon");
        classPageLayer->addChild(oneSprite);

        //float nameY = (oneSprite->getPosition().y)-(oneSprite->getBoundingBox().size.height/2);
        auto label = Label::createWithSystemFont(".", "fonts/content.ttf", 24.0);
        label->setColor(cocos2d::Color3B::WHITE);//名字颜色：00 D1 F1
        label->setAnchorPoint(Vec2(0,0.5));
        label->setPosition(Vec2(oneSprite->getPosition().x+oneSprite->getBoundingBox().size.width,cellHeight/2));
        label->setName("name");
        classPageLayer->addChild(label);

        auto labelMsgBody = Label::createWithSystemFont("", "fonts/content.ttf", 32.0);
        labelMsgBody->setColor(cocos2d::Color3B::WHITE);//名字颜色：00 D1 F1
        labelMsgBody->setAnchorPoint(Vec2(0,0.5));
        labelMsgBody->setPosition(Vec2(label->getPosition().x + label->getBoundingBox().size.width + 10, cellHeight*0.5));
        labelMsgBody->setName("msg_body");
        classPageLayer->addChild(labelMsgBody);

        //labelMsgBody->getPosition().x+labelMsgBody->getContentSize().width+33
        classPageLayer->setContentSize(Size(tableLayerWidth, cellHeight));

        //==== mask ====
        auto mask = Sprite::create("talking_bar_mask.png");
        mask->setAnchorPoint(Vec2(0, 0));
        mask->setName("mask");
        mask->setScaleX(classPageLayer->getContentSize().width/mask->getContentSize().width);
        mask->setScaleY(classPageLayer->getContentSize().height/mask->getContentSize().height);

        auto clipNode = ClippingNode::create();
        clipNode->setAlphaThreshold(0.0f);
        clipNode->setName("cliping_layer");
        clipNode->setStencil(mask);
        clipNode->addChild(classPageLayer);
        clipNode->setAnchorPoint(Vec2(0, 0));
        clipNode->setPosition(Vec2(commentTVSize.x, cellPadding));
        clipNode->setVisible(false);
        cell->addChild(clipNode);
    }
    /*
    void fillCeilByCommentList(TableViewCell *cell,ssize_t idx)
    {
        if(oneSioStatInfo.commentListVec.size()  == 0) {
            fillCeilByEmptyCeil(cell);
            return;
        }

        float cellHeight = (commentTVSize.y/tableNumPage)*0.8;
        float cellPadding = (commentTVSize.y/tableNumPage)*0.2;

        //LayerColor* classPageLayer = LayerColor::create(Color4B(30+idx*5,20+idx*10,5+idx*11, 100), commentTV->getContentSize().width, cellHeight);
        LayerColor* classPageLayer = LayerGradient::create(Color4B(16,119,254,250),Color4B(103,166,255,250),Vec2(1,0));
        classPageLayer->setName("one_row_layer");
        classPageLayer->setAnchorPoint(Vec2(0, 0));//左下角
        classPageLayer->setPosition(Vec2(0,0));

        int headNum = cocos2d::random(1,5);
        std::string gender = "male";
        if(oneSioStatInfo.commentListVec[idx].userInfo.gender == "2"){
            gender = "female";
        }

        auto label = Label::createWithSystemFont(StringUtils::format("%d)%s",idx,oneSioStatInfo.commentListVec[idx].userInfo.nickname.c_str()), "fonts/content.ttf", 24.0);
        label->setColor(cocos2d::Color3B::WHITE);//名字颜色：00 D1 F1
        label->setAnchorPoint(Vec2(0,0));
        label->setPosition(Vec2(33,0));
        label->setName("name");
        classPageLayer->addChild(label);

        auto oneSprite = Sprite::create(StringUtils::format("%s-icon%d.png",gender.c_str(),headNum));
        oneSprite->setAnchorPoint(Vec2(0.5, 1));//左下角
        oneSprite->setScale((cellHeight*0.7)/oneSprite->getContentSize().height);
        oneSprite->setPosition(Vec2(label->getContentSize().width/2+33, cellHeight));
        oneSprite->setName("icon");
        classPageLayer->addChild(oneSprite);

        auto labelMsgBody = Label::createWithSystemFont(oneSioStatInfo.commentListVec[idx].msg.msgBody.c_str(), "fonts/content.ttf", 32.0);
        labelMsgBody->setColor(cocos2d::Color3B::WHITE);//名字颜色：00 D1 F1
        labelMsgBody->setAnchorPoint(Vec2(0,0.5));
        labelMsgBody->setPosition(Vec2(label->getPosition().x + label->getBoundingBox().size.width + 33, cellHeight*0.5));
        labelMsgBody->setName("msg_body");
        classPageLayer->addChild(labelMsgBody);

        classPageLayer->setContentSize(Size(tableLayerWidth, cellHeight));
        //labelMsgBody->getPosition().x+labelMsgBody->getContentSize().width+33
        //==== mask ====
        auto mask = Sprite::create("talking_bar_mask.png");
        mask->setAnchorPoint(Vec2(0, 0));
        mask->setScaleX(classPageLayer->getContentSize().width/mask->getContentSize().width);
        mask->setScaleY(classPageLayer->getContentSize().height/mask->getContentSize().height);

        auto clipNode = ClippingNode::create();
        clipNode->setAlphaThreshold(0.0f);
        clipNode->setName("cliping_layer");
        clipNode->setStencil(mask);
        clipNode->addChild(classPageLayer);
        clipNode->setAnchorPoint(Vec2(0, 0));
        clipNode->setPosition(Vec2(commentTVSize.x, cellPadding));
        //clipNode->setTag(oneSioStatInfo.commentListVec[idx].msg.id);

        cell->addChild(clipNode);
    }
    */
    virtual ssize_t numberOfCellsInTableView(cocos2d::extension::TableView *table)override{
        return 1000;//oneSioStatInfo.commentListVec.size();
    }
    void setSomeTalkingTable(SIOCommentList &talkingInfo)
    {
        oneSioStatInfo.commentListVec.push_back(talkingInfo);
        commentTV->updateCellAtIndex(oneSioStatInfo.commentListVec.size()-1);
        playingSong("bobo.mp3");
        //if(oneSioStatInfo.commentListVec.size() > (tableNumPage+1)) {
        scrollCommentTv();
        //}
    }

    void checkoutGlobal()
    {
        connectBleLabel = nullptr;

        // actions
        this->stopAllActions();
        // timers
        this->unscheduleAllCallbacks();

        SocketIOHelper::delegate =  static_cast<SocketIOHelperDelegate *>(nullptr);
        BlueToothHelper::notifyTarget = static_cast<BlueToothHelperDelegate *>(nullptr);
    }

    void initSIOtalking(SIOCommentList &talkingInfo,const std::string &jsonRaw)
    {
        rapidjson::Document document;
        document.Parse(jsonRaw.c_str());

        if(document.HasMember("roomId")){
            talkingInfo.userInfo.roomId = document["roomId"].GetString();
        }

        if(document.HasMember("signature")){
            talkingInfo.userInfo.signature = document["signature"].GetString();
        }

        if(document.HasMember("avatar")){
            talkingInfo.userInfo.avatar = document["avatar"].GetString();
        }
        if(document.HasMember("gender")){
            talkingInfo.userInfo.gender = document["gender"].GetString();
        }
        if(document.HasMember("role")){
            talkingInfo.userInfo.role = document["role"].GetString();
        }
        if(document.HasMember("signature")){
            talkingInfo.userInfo.signature = document["signature"].GetString();
        }
        if(document.HasMember("nickname")){
            talkingInfo.userInfo.nickname = document["nickname"].GetString();
        }

        if(document.HasMember("msg")){
            const rapidjson::Value& childValue = document["msg"];

            if(childValue.HasMember("msgType")){
                talkingInfo.msg.msgType = childValue["msgType"].GetString();
            }
            if(childValue.HasMember("canvasId")){
                talkingInfo.msg.canvasId = childValue["canvasId"].GetString();
            }

            if(talkingInfo.msg.msgType == "heart"){
                talkingInfo.msg.msgBody = "❤❤❤";
            }else {
                if (childValue.HasMember("msgBody")) {
                    talkingInfo.msg.msgBody = childValue["msgBody"].GetString();
                }
            }
        }
    }
    void playingSong(std::string flag,float dlta=1.0f){
        AudioEngine::play2d(flag);

        this->scheduleOnce([=](float dt) {
            SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
        },dlta ,"resumeBackgroundMusic");
    }
    void initSIOoffline(std::map<std::string,std::string> &offlineMap,const std::string &jsonRaw)
    {
        rapidjson::Document document;
        document.Parse(jsonRaw.c_str());

        if(document.HasMember("roomId")){
            offlineMap["roomId"] = document["roomId"].GetString();
        }

        //int signature = -1;
        if(document.HasMember("signature")){
            offlineMap["signature"] = document["signature"].GetString();
        }

        //TODO: 隐藏用户的小点
    }


    void initSIOStatInfo(const std::string &jsonRaw)
    {
        oneSioStatInfo.init();

        rapidjson::Document document;
        document.Parse(jsonRaw.c_str());

        int redNum = -1;
        if(document.HasMember("redNum")){
            oneSioStatInfo.redNum = document["redNum"].GetInt();
        }

        int commentNum = -1;
        if(document.HasMember("commentNum")){
            oneSioStatInfo.commentNum = document["commentNum"].GetInt();
        }

        int visitNum = -1;
        if(document.HasMember("visitNum")){
            oneSioStatInfo.visitNum = document["visitNum"].GetInt();
        }

        if(document.HasMember("commentList")){
            const rapidjson::Value& childValue = document["commentList"];

            rapidjson::SizeType ixx = childValue.Size();
            for(rapidjson::SizeType i = 0; i < childValue.Size(); ++i){
                const rapidjson::Value& commentListChildValue = childValue[i];

                SIOCommentList oneSCL;
                oneSCL.userInfo.avatar = commentListChildValue["avatar"].GetString();
                oneSCL.userInfo.nickname = commentListChildValue["nickname"].GetString();
                oneSCL.userInfo.role = commentListChildValue["role"].GetString();
                oneSCL.userInfo.roomId = commentListChildValue["roomId"].GetString();
                oneSCL.userInfo.gender = commentListChildValue["gender"].GetString();
                oneSCL.userInfo.signature = commentListChildValue["signature"].GetString();

                oneSCL.msg.canvasId = commentListChildValue["msg"]["canvasId"].GetString();
                oneSCL.msg.msgBody = commentListChildValue["msg"]["msgBody"].GetString();
                oneSCL.msg.msgType = commentListChildValue["msg"]["msgType"].GetString();
                oneSCL.msg.id = commentListChildValue["msg"]["id"].GetInt();
                oneSCL.msg.timestamp = 0;

                oneSioStatInfo.commentListVec.push_back(oneSCL);

                if((tableNumPage-i)<=0){
                    break;
                }
            }

            std::reverse(std::begin(oneSioStatInfo.commentListVec), std::end(oneSioStatInfo.commentListVec));
        }
    }

    void initSocketIO(bool isForceConn=false){
        float delta = 1.0f+CCRANDOM_0_1();
        this->scheduleOnce([=](float dt) {
            sioClientIsConnected = false;
            SocketIOHelper::checkConnection(isForceConn);
        },delta ,"initSocketIO");
    };

    void initRoomCommentator(const std::string& msg)
    {
        rapidjson::Document document;
        document.Parse(msg.c_str());
        sioUserInfoVec.clear();

        for(rapidjson::SizeType i = 0; i < document.Size(); ++i){
            if(document[i].IsNull()){
                continue;
            }

            std::string oneUserInfoStr = document[i].GetString();

            rapidjson::Document documentUI;
            documentUI.Parse(oneUserInfoStr.c_str());

            SIOUserInfo oneUserInfo;

            if(documentUI.HasMember("roomId")){
                oneUserInfo.roomId = documentUI["roomId"].GetString();
            }
            if(documentUI.HasMember("role")){
                oneUserInfo.role = documentUI["role"].GetString();
            }
            if(documentUI.HasMember("avatar")){
                oneUserInfo.avatar = documentUI["avatar"].GetString();
            }
            if(documentUI.HasMember("nickname")){
                oneUserInfo.nickname = documentUI["nickname"].GetString();
            }
            if(documentUI.HasMember("gender")){
                oneUserInfo.gender = documentUI["gender"].GetString();
            }
            if(documentUI.HasMember("signature")){
                oneUserInfo.signature = documentUI["signature"].GetString();
            }
            if(documentUI.HasMember("lastSign")){
                oneUserInfo.lastSign = documentUI["lastSign"].GetString();
            }

            sioUserInfoVec.push_back(oneUserInfo);
            /*
             { roomId: 'ZXYB00000001_6_2_1',
              role: 'ND_PAD',
              avatar: 'avatar',
              nickname: 'nickname',
              gender: 'gender',
              signature: 'signature123',
              lastSign: '' }

             * */
        }
    }

    void makeFloatingArea()
    {
        auto oneL = this->getChildByName("tianLayer");
        if(oneL == nullptr)
            return;
        LayerColor* classPageLayer = LayerColor::create(Color4B(255,255,255, 0), (visibleSize.width-oneL->getContentSize().width)/2, oneL->getContentSize().height);
        classPageLayer->setAnchorPoint(Vec2(0, 0));//左下角
        classPageLayer->setPosition(Vec2(oneL->getContentSize().width,0));
        classPageLayer->addComponent(PhysicsBody::createEdgeBox(Size((visibleSize.width-oneL->getContentSize().width)/2, visibleSize.height)));
        classPageLayer->setName("floatingSIOiconArea");
        oneL->addChild(classPageLayer);

/*
        auto wall = Node::create();
        wall->addComponent(PhysicsBody::createEdgeBox(Size((visibleSize.width-oneL->getContentSize().width)/2, visibleSize.height)));
        wall->setPosition(Vec2(0,0));
        wall->setAnchorPoint(Vec2(0, 0));//左下角
        addChild(wall);
*/

    }

    void setUserBall(SIOUserInfo oneCommentor)
    {
        auto oneL = this->getChildByName("tianLayer")->getChildByName("floatingSIOiconArea");
        if(oneL->getChildByName(oneCommentor.signature) != nullptr){
            return;
        }

        int headNum = cocos2d::random(1,5);
        string gender = "male";
        if(oneCommentor.gender == "2"){
            gender = "female";
        }
        auto oneSprite = Sprite::create(StringUtils::format("%s-icon%d.png",gender.c_str(),headNum));
        oneSprite->setAnchorPoint(Vec2(0.5, 0));//左下角
        oneSprite->setName("icon");
        //--------------------------------
        auto oneUserNode = Node::create();//LayerColor::create(Color4B(125,0,0,0), 100, 100);//Node::create();
        oneUserNode->addChild(oneSprite);
        oneUserNode->setName(oneCommentor.signature);
        oneUserNode->setOpacity(0);

        //========================
        auto detailInfoLab =  Label::createWithTTF(oneCommentor.nickname, "fonts/content.ttf",  24);
        detailInfoLab->setAnchorPoint(Vec2(0.5, 1));//左下角
        detailInfoLab->setName("name");

        oneUserNode->addChild(detailInfoLab);
        //------------------------

        auto talkInfoLab =  Label::createWithTTF("一二三四五六七八九十","fonts/content.ttf",  22);

        float tiLabWid = oneSprite->getContentSize().width*3;
        if(talkInfoLab->getContentSize().width < tiLabWid){
            tiLabWid = talkInfoLab->getContentSize().width;
        }

        talkInfoLab->setAnchorPoint(Vec2(0.5, 0.5));//左下角
        talkInfoLab->setName("talking-txt");
        talkInfoLab->enableWrap(true);
        talkInfoLab->setWidth(tiLabWid);
        talkInfoLab->setVerticalAlignment(TextVAlignment::BOTTOM);
        talkInfoLab->setVerticalAlignment(TextVAlignment::CENTER);
        talkInfoLab->setOverflow(Label::Overflow::RESIZE_HEIGHT);
        talkInfoLab->setLineBreakWithoutSpace(true);

        //talkInfoLab->setColor(cocos2d::Color3B::BLUE);

        Size backgroundT = talkInfoLab->getContentSize();
        backgroundT.width  *= 1.1;
        backgroundT.height *= 1.1;

        //backgroundT.width/2+oneSprite->getContentSize().width/2
        talkInfoLab->setPosition(backgroundT.width/2, backgroundT.height/2);
        LayerGradient *gradientT = LayerGradient::create(Color4B(16,119,254,250),Color4B(103,166,255,250),Vec2(1,0));
        //gradientT->setContentSize(Size(oneSprite->getContentSize().width/2,oneSprite->getContentSize().height+detailInfoLab->getContentSize().height));
        gradientT->setAnchorPoint(Vec2(0.5, 0));
        gradientT->setContentSize(backgroundT);
        gradientT->setName("talking-bar");
        //backgroundT.width/2
        gradientT->setPosition(Vec2(0, oneSprite->getContentSize().height));
        gradientT->addChild(talkInfoLab);
        gradientT->setVisible(false);
        //gradientT

        //=圆角掩膜================
        /*
        auto mask = Sprite::create("talking_bar_mask.png");
        mask->setAnchorPoint(Vec2(0, 0));
        mask->setScaleX(backgroundT.width/mask->getContentSize().width);
        mask->setScaleY(backgroundT.height/mask->getContentSize().height);

        auto clipNode = ClippingNode::create();
        clipNode->setAlphaThreshold(0.0f);
        clipNode->setStencil(mask);
        clipNode->addChild(gradientT);
        clipNode->setName("talking-bar");
        clipNode->setAnchorPoint(Vec2(0, 0));
        clipNode->setPosition(Vec2(0, oneSprite->getContentSize().height));
        */
        //=================

        oneUserNode->addChild(gradientT);
        //oneL->getContentSize().width/2
        oneUserNode->setPosition(Vec2(0, oneL->getContentSize().height/2));
        oneUserNode->setAnchorPoint(Vec2(0, 0));
        //--------------------------------
        oneSprite->setPosition(Vec2(backgroundT.width/2, 0));//左下角
        detailInfoLab->setPosition(backgroundT.width/2, 0);
        //--------------------------------
        Size oneUOS = oneSprite->getContentSize();
        oneUOS.width  = talkInfoLab->getContentSize().width;
        oneUOS.height = oneSprite->getContentSize().height+detailInfoLab->getContentSize().height+talkInfoLab->getContentSize().height;

        auto physicsBody = PhysicsBody::createBox(oneUOS, PHYSICSBODY_MATERIAL_DEFAULT);
        physicsBody->setGravityEnable(false);

        physicsBody->setVelocity(Vec2(cocos2d::random(-555,555),
                                      cocos2d::random(-510,555)));

        physicsBody->setRotationEnable(false);

        //设置物体的恢复力
        physicsBody->getShape(0)->setRestitution(1.0f);
        //设置物体的摩擦力
        physicsBody->getShape(0)->setFriction(0.0f);
        //设置物体密度
        physicsBody->getShape(0)->setDensity(1.0f);
        //设置质量
        //physicsBody->getShape(0)->setMass(cocos2d::random(-555,555));

        //设置物体是否受重力系数影响
        physicsBody->setGravityEnable(false);

        //设置物体的冲力
        Vect force=Vect(cocos2d::random(-500,500),cocos2d::random(-500,500));
        physicsBody->applyImpulse(force);
        oneUserNode->setContentSize(oneUOS);
        oneUserNode->setPhysicsBody(physicsBody);
        oneL->addChild(oneUserNode);

        oneUserNode->runAction(FadeIn::create(1.0f));
    }

    void bornUserIcon()
    {
        makeFloatingArea();
        for(const auto oneVisitor:sioUserInfoVec) {
            setUserBall(oneVisitor);
        }
    }

    //test event callback handlers, these will be registered with socket.io
    void SioRoomVisitors(SIOClient *client, const std::string& msg) override{

        setDebugLabel(StringUtils::format("SioRoomVisitors:%s", msg.c_str()));

        if(msg == "null") {
            return;
        }

        setSIOStatNum();

        return;

        initRoomCommentator(msg);

        bornUserIcon();
        bornUserComment();
    }

    void bornUserComment()
    {
        if(oneSioStatInfo.commentListVec.size() == 0){
            return;
        }

        auto oneL = this->getChildByName("tianLayer")->getChildByName("floatingSIOiconArea");
        for(const auto &oneCL:oneSioStatInfo.commentListVec){
            if(oneL->getChildByName(oneCL.userInfo.signature) == nullptr){
                setUserBall(oneCL.userInfo);
            }

            if(oneL->getChildByName(oneCL.userInfo.signature) == nullptr){
                continue;
            }

            if(oneCL.msg.msgBody.length()>0 &&
               oneCL.msg.msgType == "msg"
                    ) {
                auto talkingBar = oneL->getChildByName(oneCL.userInfo.signature)->getChildByName("talking-bar");
                if(!talkingBar->isVisible()){
                    talkingBar->setVisible(true);
                }
                //if(oneCL.userInfo.nickname == "晓彬")
                setUserBallTalkingBar(static_cast<Label*>(talkingBar->getChildByName("talking-txt")), oneCL.msg);
            }
        }
    }

    void setUserBallHeartTable(size_t commentListNum, SIOCommentListMsgBody oneCLMsg)
    {
        Vec2 oneWordPos = getScreenPos(oneCLMsg.canvasId);

        TableViewCell* oneSprite = static_cast<TableViewCell*>(commentTV->cellAtIndex(commentListNum));
        if(oneSprite == nullptr){
            return;
        }

        Vec2 spritePos = getScreenPos(static_cast<Node*>(oneSprite->getChildByName("cliping_layer")));
        if(spritePos.x == 0 ||
           spritePos.y == 0
                ){
            return;
        }

        Sprite *oneHeart = Sprite::createWithTexture(reddiggTexture);
        oneHeart->setAnchorPoint(Vec2(0, 0.5));
        oneHeart->setPosition(spritePos);
        oneHeart->setScale(1.0f);
        // create a Spawn to use

        this->addChild(oneHeart);

        float scaleNum = cocos2d::random(0,4)*CCRANDOM_0_1();
        if(scaleNum==0){
            scaleNum = 1;
        }

        oneHeart->runAction(Sequence::create(Spawn::create(
                ScaleBy::create(1.2f, scaleNum),
                FadeTo::create(1.2f, 20),
                MoveTo::create(1.2f, oneWordPos),
                nullptr
                                             ),
                                             CallFunc::create(
                                                     CC_CALLBACK_0(Sprite::removeFromParent,
                                                                   oneHeart)),
                                             nullptr
                            )
        );

    }

    void setUserBallHeart(Node* oneUserN, SIOCommentListMsgBody oneCLMsg)
    {
        if(oneUserN == nullptr){
            return;
        }

        Vec2 oneWordPos = getScreenPos(oneCLMsg.canvasId);

        Sprite* oneSprite = static_cast<Sprite*>(oneUserN->getChildByName("icon"));

        Vec2 spritePos = getScreenPos(static_cast<Node*>(oneSprite));
        if(spritePos.x == 0 ||
           spritePos.y == 0
                ){
            return;
        }

        Sprite *oneHeart = Sprite::createWithTexture(reddiggTexture);
        oneHeart->setAnchorPoint(Vec2(0, 0.5));
        oneHeart->setPosition(spritePos);
        oneHeart->setScale(1.0f);
        // create a Spawn to use

        this->addChild(oneHeart);

        oneHeart->runAction(Sequence::create(Spawn::create(
                ScaleBy::create(1.2f, 4.0f),
                FadeTo::create(1.2f, 20),
                MoveTo::create(1.2f, oneWordPos),
                nullptr
                                             ),
                                             CallFunc::create(
                                                     CC_CALLBACK_0(Sprite::removeFromParent,
                                                                   oneHeart)),
                                             nullptr
                            )
        );

    }

    void setUserBallTalkingBar(Label* talkInfoLab, SIOCommentListMsgBody oneCLMsg,bool needAct=false)
    {
        talkInfoLab->setString(oneCLMsg.msgBody);

        LayerGradient  *gradientT  = static_cast<LayerGradient *>(talkInfoLab->getParent());
        Node* oneUserNode = talkInfoLab->getParent()->getParent();
        Sprite* oneSprite = static_cast<Sprite*>(oneUserNode->getChildByName("icon"));
        Label* detailInfoLab = static_cast<Label*>(oneUserNode->getChildByName("name"));
        //========================
        float tiLabWid = oneSprite->getContentSize().width*3;

        if(oneCLMsg.msgBody.length()<30){
            tiLabWid = (tiLabWid/10)*(oneCLMsg.msgBody.length()/3);
        }
        //if(talkInfoLab->getContentSize().width < tiLabWid){
        //  tiLabWid = talkInfoLab->getContentSize().width;
        //}

        talkInfoLab->setAnchorPoint(Vec2(0.5, 0.5));//左下角
        talkInfoLab->enableWrap(true);
        talkInfoLab->setWidth(tiLabWid);
        talkInfoLab->setVerticalAlignment(TextVAlignment::BOTTOM);
        talkInfoLab->setVerticalAlignment(TextVAlignment::CENTER);
        talkInfoLab->setOverflow(Label::Overflow::RESIZE_HEIGHT);
        talkInfoLab->setLineBreakWithoutSpace(true);

        //talkInfoLab->setColor(cocos2d::Color3B::BLUE);
        Size backgroundT = talkInfoLab->getContentSize();

        backgroundT.width  *= 1.1;
        backgroundT.height *= 1.2;

        //backgroundT.width/2+oneSprite->getContentSize().width/2
        talkInfoLab->setPosition(backgroundT.width/2, backgroundT.height/2);

        //gradientT->setContentSize(Size(oneSprite->getContentSize().width/2,oneSprite->getContentSize().height+detailInfoLab->getContentSize().height));
        gradientT->setAnchorPoint(Vec2(0.5, 0));
        gradientT->setContentSize(backgroundT);
        gradientT->setName("talking-bar");
        //backgroundT.width/2
        gradientT->setPosition(Vec2(0, oneSprite->getContentSize().height));

        detailInfoLab->setPosition(backgroundT.width/2, 0);

        //oneL->getContentSize().width/2
        //oneUserNode->setPosition(Vec2(0, oneL->getContentSize().height/2));
        //oneUserNode->setAnchorPoint(Vec2(0, 0));
        Size oneUOS = oneSprite->getContentSize();
        oneUOS.width  = talkInfoLab->getContentSize().width;
        oneUOS.height = oneSprite->getContentSize().height+detailInfoLab->getContentSize().height+talkInfoLab->getContentSize().height;

        oneUserNode->setContentSize(oneUOS);
        //--------------------------------
        detailInfoLab->setAnchorPoint(Vec2(0.5, 1));//左下角
        oneSprite->setPosition(Vec2(oneUOS.width/2, 0));//左下角
        detailInfoLab->setPosition(oneUOS.width/2, 0);
        //--------------------------------

        if(needAct) {
            auto scale = ScaleBy::create(0.4f, 2.0f);
            auto scaleRev = ScaleBy::create(0.1f, 0.5f);
            gradientT->runAction(Sequence::create(scale, scaleRev, nullptr));
        }
    }

    //test event callback handlers, these will be registered with socket.io
    void SioRoomCommentator(SIOClient *client, const std::string& msg)override {
        return;
        setDebugLabel(StringUtils::format("SioRoomCommentator:%s", msg.c_str()));

        initRoomCommentator(msg);
        bornUserIcon();
    }

    //test event callback handlers, these will be registered with socket.io
    void SioTalking(SIOClient *client, const std::string& msg)override {
        //setDebugLabel(StringUtils::format("SioOffline:%s",msg.c_str()));
        this->scheduleOnce([=](float dt) {
            SIOCommentList talkingInfo;
            initSIOtalking(talkingInfo, msg);

            //TODO: 聊天
            if(talkingInfo.msg.msgType == "msg"){
                oneSioStatInfo.commentNum++;
                setNumByStatName("comment",oneSioStatInfo.commentNum);
                //setSomeTalking(talkingInfo);
                setSomeTalkingTable(talkingInfo);
            }

            if(talkingInfo.msg.msgType == "heart"){
                oneSioStatInfo.redNum++;
                setNumByStatName("reddigg",oneSioStatInfo.redNum);
                //setSomeHeart(talkingInfo);
                setSomeHeartTable(talkingInfo);
            }
        },0 ,"heart");
    };

    void setSomeHeartTable(SIOCommentList &talkingInfo){
        oneSioStatInfo.commentListVec.push_back(talkingInfo);
        commentTV->updateCellAtIndex(oneSioStatInfo.commentListVec.size()-1);

        scrollCommentTv();

        if(talkingInfo.msg.canvasId.length()>0 &&
           talkingInfo.msg.msgType == "heart"
                ){
            //setUserBallHeartTable(oneSioStatInfo.commentListVec.size()-1, talkingInfo.msg);
            sendingHeartByTime(oneSioStatInfo.commentListVec.size()-1, talkingInfo.msg,5);
        }
    };

    void sendingHeartByTime(size_t commentListNum, SIOCommentListMsgBody oneCLMsg,int heartNum)
    {

        this->scheduleOnce([=](float dt) {
            setUserBallHeartTable(commentListNum,oneCLMsg);

            if(heartNum >= 0) {
                playingSong("woo.mp3");
                sendingHeartByTime(commentListNum, oneCLMsg, heartNum-1);
            }
        },CCRANDOM_0_1()/5 ,"heart");
    }

    void setSomeHeart(SIOCommentList &talkingInfo){
        auto oneL = this->getChildByName("tianLayer")->getChildByName("floatingSIOiconArea");
        if(oneL == nullptr){
            return;
        }

        if(oneL->getChildByName(talkingInfo.userInfo.signature) == nullptr){
            setUserBall(talkingInfo.userInfo);
        }

        if(oneL->getChildByName(talkingInfo.userInfo.signature) == nullptr){
            return;
        }

        if(talkingInfo.msg.canvasId.length()>0 &&
           talkingInfo.msg.msgType == "heart"
                ){
            Node* userN = oneL->getChildByName(talkingInfo.userInfo.signature);
            setUserBallHeart(userN, talkingInfo.msg);
        }
    };

    Vec2 getScreenPos(std::string &canvasId){
        Vec2 oneP = Vec2(0, 0);

        if(idMappingDrawNode.count(canvasId) == 0){
            return oneP;
        }

        auto tbst1 = idMappingDrawNode[canvasId];
        oneP = tbst1->getParent()->convertToWorldSpace(tbst1->getPosition());
        return oneP;
    }

    Vec2 getScreenPos(Node* tbst1){
        Vec2 oneP = Vec2(0, 0);

        oneP = tbst1->getParent()->convertToWorldSpace(tbst1->getPosition());
        return oneP;
    }

    void setSomeTalking(SIOCommentList &talkingInfo){
        auto oneL = this->getChildByName("tianLayer")->getChildByName("floatingSIOiconArea");
        if(oneL == nullptr){
            return;
        }

        if(oneL->getChildByName(talkingInfo.userInfo.signature) == nullptr){
            setUserBall(talkingInfo.userInfo);
        }

        if(oneL->getChildByName(talkingInfo.userInfo.signature) == nullptr){
            return;
        }

        if(talkingInfo.msg.msgBody.length()>0 &&
           talkingInfo.msg.msgType == "msg"
                ){
            auto talkingBar = oneL->getChildByName(talkingInfo.userInfo.signature)->getChildByName("talking-bar");
            if(!talkingBar->isVisible()){
                talkingBar->setVisible(true);
            }

            //if(oneCL.userInfo.nickname != "晓彬")
            setUserBallTalkingBar(static_cast<Label*>(talkingBar->getChildByName("talking-txt")), talkingInfo.msg,true);
        }
    }

    //test event callback handlers, these will be registered with socket.io
    void SioOffline(SIOClient *client, const std::string& msg)override {
        setDebugLabel(StringUtils::format("SioOffline:%s",msg.c_str()));


        std::map<std::string,std::string> offlineInfo;
        initSIOoffline(offlineInfo, msg);
        //TODO: 去掉在线小点

    };

    void SioShareCode(SIOClient *client, const std::string& url) override{
        if(url.length() == 0){
            SIOQRMd5.clear();
            return;
        }
        this->scheduleOnce([=](float dt) {
            std::string jUrl = url.substr(1,url.length()-2);
            downloadFriend(jUrl, "分享二维码");
        },0.0f ,"分享二维码");
    };

    //test event callback handlers, these will be registered with socket.io
    void SioStoreRoomid(SIOClient *client, const std::string& md5)override {
        setDebugLabel(StringUtils::format("SioStoreRoomid:%s",md5.c_str()));

        if(md5.length()<3){
            return;
        }

        std::string jmd5 = md5.substr(1,md5.length()-2);
        if (SIOQRMd5 != jmd5) {
            SIOQRMd5 = jmd5;
            SocketIOHelper::getInstant()->emit("share-code", jmd5);
        }
    };

    virtual void SioOnConnect(SIOClient* client) override{
        std::string channelName = "fake-channel-name";
        if(BlueToothHelper::connectBleMacId.length() > 0){
            channelName = BlueToothHelper::connectBleMacId;
        }

        if(channelName == "00-00-00-00-00-00" ||
           BlueToothHelper::connectBleMacId.length() <= 0
        ){
            std::random_device rd;                         // A function object for generating seeds
            channelName = StringUtils::format("%udL%udL%ud",rd(), rd(), rd());
            if(channelName.length() > 32){
                channelName = channelName.substr(0,32);
            }
        }
        LOGD("store-roomid SioOnConnect channelName=%s",channelName.c_str());

        SioJoinRoom();
    };

    void setSIOStatNum()
    {
        setNumByStatName("visitor",oneSioStatInfo.visitNum);
        setNumByStatName("reddigg",oneSioStatInfo.redNum);
        setNumByStatName("comment",oneSioStatInfo.commentNum);
    }

    //test event callback handlers, these will be registered with socket.io
    void SioStatInfo(SIOClient *client, const std::string& data)override {
        sioClientIsConnected = true;

        initSIOStatInfo(data);

        //std::vector<SIOCommentList> commentListVecxx = oneSioStatInfo.commentListVec;
        setDebugLabel(StringUtils::format("SioStatInfo:%s",data.c_str()));

        SocketIOHelper::getInstant()->emit("room-visitors", "");

        checkExistTableView();
    };

    void checkExistTableView(){
        if(isTableLoadData){
            return;
        }

        isTableLoadData = true;
        initTableView();

        if(oneSioStatInfo.commentListVec.size() < 1){
            return;
        }

        for(int i=0;i<oneSioStatInfo.commentListVec.size();i++){
            commentTV->updateCellAtIndex(i);
        }

        scrollCommentTv(oneSioStatInfo.commentListVec.size());

    }

    //test event callback handlers, these will be registered with socket.io
    void SioOnline(SIOClient *client, const std::string& data) override {
        setDebugLabel(StringUtils::format("SioOnline:%s",data.c_str()));
    };
    //test event callback handlers, these will be registered with socket.io
    void SioConnection(SIOClient *client, const std::string& data) override{
        setDebugLabel(StringUtils::format("SioConnection:%s", data.c_str()));

        SioJoinRoom();
    }
    void SioJoinRoom(){
        std::string channelName = "fake-channel-name";
        if(BlueToothHelper::connectBleMacId.length() > 0){
            channelName = BlueToothHelper::connectBleMacId;
        }

        if(channelName == "00-00-00-00-00-00" ||
           BlueToothHelper::connectBleMacId.length() <= 0
        ){
            std::random_device rd;                         // A function object for generating seeds
            channelName = StringUtils::format("%udL%udL%ud",rd(), rd(), rd());
            if(channelName.length() > 32){
                channelName = channelName.substr(0,32);
            }
        }

        channelName.append(StringUtils::format("_%d_%d_%d",classNum,termNo,pageNo));
        if(channelName == SIOjoinRoom){
            return;
        }

        SIOjoinRoom = channelName;
        oneSIOWordPos.clear();

        SocketIOHelper::getInstant()->emit("store-roomid", channelName);
        LOGD("store-roomid SioJoinRoom channelName=%s",channelName.c_str());

        channelName.append("\r\nND_PAD\r\navatorOTT\r\n智慧好字帖\r\n1\r\nsignatureOTT\r\n ");
        setDebugLabel(channelName);

        SocketIOHelper::getInstant()->emit("join-room", channelName);
    };
    virtual void SioOnMessage(SIOClient* client, const std::string& data) override{

    };

    /**
	*  @brief Used for network level socket close (not for disconnect from the socket.io server)
	*/
    virtual void SioOnClose(cocos2d::network::SIOClient* client)override
    {
        SIOjoinRoom.clear();
        initSocketIO(true);
        setDebugLabel(StringUtils::format("SocketIo-OnClose"));
    }

    /**
    *  @brief Used for network level socket error (not for disconnect from the socket.io server)
    **/
    virtual void SioOnError(cocos2d::network::SIOClient* client, const std::string& data)override
    {
        SIOjoinRoom.clear();
        initSocketIO(true);
        setDebugLabel(StringUtils::format("SocketIo-onError:%s", data.c_str()));
    }

    void clearTianAndInit(){
        HttpClient::getInstance()->setClearRequestPredicate(nullptr);
        HttpClient::getInstance()->setClearResponsePredicate(nullptr);
        HttpClient::getInstance()->clearResponseAndRequestQueue();

        storePageInfo(HandTianScene::pageNo);
        checkoutGlobal();
        auto scene = HandTianScene::createScene();
        Director::getInstance()->replaceScene(scene);

        return;
        /*
        curClassPageChooser = CHANGE_PAGE;
        clearTian();

        this->scheduleOnce([&](float dt) {
            while(true) {
                auto tianLayer = static_cast<LayerColor *>(this->getChildByName("tianLayer"));
                if (tianLayer == nullptr) {
                    break;
                }
            }
            initTian();
        },0.1 ,"clearTianAndInitInterval");
        */
    }

    void clearTian()
    {
        //this->unschedule(CC_SCHEDULE_SELECTOR(HandTianScene::drawDynamicTian));
        // actions
        this->stopAllActions();
        // timers
        this->unscheduleAllCallbacks();

        Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
            hideMask();
            auto oneL = this->getChildByName("tianLayer");
            if(oneL != nullptr){
                oneL->removeAllChildren();
                oneL->removeFromParent();
            }
        });
    }

    void initTian(bool isDrawTemplateLayer=false)
    {
        initTemplateLayers();

        initMask();

        if(true) {
            initGifEvent();
            checkOffsetCheck();
        }

        initDataForDraw();

        initPaegStatNum();

        selectedBarPos = 12;
        isTableLoadData = false;//没读过列表

        initTestNode(false);
    }

    void initPaegStatNum()
    {
        if(this->getChildByName("page-stat-num") == nullptr){
            initPageStatLayer();
        }else{
            setNumByStatName("visitor","浏览");
            setNumByStatName("reddigg","点赞");
            setNumByStatName("comment","评论");
        }
    }

    void initPageStatLayer()
    {
        initPageOutLayer();
        initOneStatNum(0,"reddigg_num","reddigg_num.png","reddigg_num_icon","reddigg_num_txt","点赞");
        initOneStatNum(1,"comment_num","comment_num.png","comment_num_icon","comment_num_txt","评论");
        initOneStatNum(2,"visitor_num","visitor_num.png","visitor_num_icon","visitor_num_txt","浏览");
        //initRedDiggNum();
        //initCommentNum();
        //initVisitorNum();
    }

    Label * getStatFieldByName(const char *name)
    {
        std::string layerName = StringUtils::format("%s_num", name);
        std::string textName = StringUtils::format("%s_num_txt", name);

        auto pageOL = this->getChildByName("page-stat-num");
        if(pageOL == nullptr){
            return nullptr;
        }

        auto oneLayer = pageOL->getChildByName(layerName);
        if(oneLayer == nullptr){
            return nullptr;
        }

        Label* oneLabel = static_cast<Label*>(oneLayer->getChildByName(textName));
        return oneLabel;
    }

    void setNumByStatName(const char* name,const char*cnt){
        Label* oneLabel = getStatFieldByName(name);
        if(oneLabel == nullptr){
            return;
        }

        oneLabel->setString(cnt);
    }

    void setNumByStatName(const char* name,int num){
        Label* oneLabel = getStatFieldByName(name);
        if(oneLabel == nullptr){
            return;
        }

        oneLabel->setString(StringUtils::format("%d", num));
    }

    void initPageOutLayer()
    {
        auto oneL = this->getChildByName("tianLayer");
        Size tlSize = oneL->getContentSize();
        Vec2 tlPos  = oneL->getPosition();

        Vec2 oneLPos;
        oneLPos.x = tlPos.x+tlSize.width;
        oneLPos.y = tlPos.y+tlSize.height;

        Size oneLSize;
        oneLSize.width = visibleSize.width - (tlPos.x+tlSize.width);
        oneLSize.height = visibleSize.height - (tlPos.y+tlSize.height);

        Size scaleLSize = oneLSize;
        scaleLSize.width = oneLSize.width*0.8;
        scaleLSize.height = oneLSize.height*0.8;
        oneLPos.x += oneLSize.width-scaleLSize.width;

        auto paegOL = LayerColor::create(Color4B(255, 255, 255, 0), scaleLSize.width, scaleLSize.height);//Node::create();//Color4B(125,0,0,125), 100, 100);//Node::create();
        paegOL->setName("page-stat-num");
        paegOL->setAnchorPoint(Vec2(0, 0));
        paegOL->setPosition(oneLPos);

        this->addChild(paegOL);
    }
    void initOneStatNum(int byNum,const char* layerName,const char* iconPath,const char*iconName,const char*labName,const char* promptC)
    {
        auto pageOL = this->getChildByName("page-stat-num");

        Size numSize = pageOL->getContentSize();
        Vec2 numPos  = pageOL->getPosition();

        numSize.width /= 3;

        numPos.x = numSize.width*byNum;
        numPos.y = 0;
        //numSize.width /= 3;
        //numSize.height /= 3;

        auto numOL = LayerColor::create(Color4B(0, 255, 0, 0), numSize.width, numSize.height);//Node::create();//Color4B(125,0,0,125), 100, 100);//Node::create();
        numOL->setName(layerName);
        numOL->setAnchorPoint(Vec2(0, 0));
        numOL->setPosition(numPos);

        initIconNumByName(numOL,iconPath,iconName,labName, promptC);

        pageOL->addChild(numOL);
    }


    void initIconNumByName(Node* oneOL,const char* iconPath,const char*iconName,const char*labName,const char* promptC)
    {
        Size numOL = oneOL->getContentSize();
        Size sprintSize  = numOL*0.6;

        auto spriteB1 = Sprite::create(iconPath);
        spriteB1->setScale(sprintSize.height/spriteB1->getContentSize().height);
        spriteB1->setAnchorPoint(Vec2(1, 0.5));//左下角
        //spriteB1->setScaleY((sprintSize.height)/spriteB1->getContentSize().height);
        spriteB1->setName(iconName);
        spriteB1->setPosition(Vec2(numOL.width/2, numOL.height/2));
        oneOL->addChild(spriteB1);

        auto detailInfoLab =  Label::createWithTTF(promptC, "fonts/content.ttf",  32);
        detailInfoLab->setAnchorPoint(Vec2(0, 0.5));//左下角
        detailInfoLab->setPosition(Vec2(numOL.width/2+7, numOL.height/2));
        detailInfoLab->setName(labName);
        oneOL->addChild(detailInfoLab);
    }

    void initMaskPrompt(LayerColor *maskColLayer, std::string prompt, Vec2 positionVec, std::string boardNmaePrefix)
    {
        std::string boardNmae = boardNmaePrefix+"_txt";
        auto detailInfoLab =  Label::createWithTTF(prompt, "fonts/content.ttf",  28);
        detailInfoLab->setAnchorPoint(Vec2(0, 0));//左下角
        detailInfoLab->setPosition(positionVec);
        detailInfoLab->setName(boardNmae);

        //前边的 logo
        std::string downName = boardNmaePrefix+"_logo_down";
        auto spriteB1 = Sprite::create("down.png");
        spriteB1->setAnchorPoint(Vec2(1.5, 0));//左下角
        spriteB1->setPosition(Vec2(0, 0));
        spriteB1->setName(downName);
        detailInfoLab->addChild(spriteB1);

        //前边的 logo
        std::string okName = boardNmaePrefix+"_logo_ok";
        spriteB1 = Sprite::create("ok.png");
        spriteB1->setAnchorPoint(Vec2(1.5, 0));//左下角
        spriteB1->setPosition(Vec2(0, 0));
        spriteB1->setName(okName);
        spriteB1->setVisible(false);
        detailInfoLab->addChild(spriteB1);

        maskColLayer->addChild(detailInfoLab);
    }

    void hideMask(){
        LayerColor* oneMaskCover = static_cast<LayerColor*>(this->getChildByName("mask-cover"));

        if(oneMaskCover != nullptr) {
            oneMaskCover->removeFromParent();//setVisible(false);
        }
    }

    void setPreparingTianByMask(){
        //第一排。。。。。。。。。。。。。。。。
        std::string termName = "上";
        if(termNo == 2){
            termName = "下";
        }
        resetMaskInfoBy("board_1",
                        StringUtils::format("下载 %d 年级第 %d 页(%s学期)字帖信息",classNum,pageNo,termName.c_str()),
                        false,
                        true
        );
    }

    void setPrepareTianWordsMaskById(std::string str)
    {
        std::string prompt = StringUtils::format("下载详细数据文字信息(%s)", str.c_str());

        //第二排
        resetMaskInfoBy("board_2",
                        prompt,
                        false,
                        true
        );
    }

    void setDrawAllToCanvasMaskById(std::string str,int curNum,int totalNum,bool isVDown=true,bool isVOk=false)
    {
        std::string prompt = StringUtils::format("分析，绘制字帖信息:%s(%d/%d)", str.c_str(),curNum,totalNum);

        //第二排
        resetMaskInfoBy("board_3",
                        prompt,
                        isVDown,
                        isVOk
        );
    }

    void resetMaskInfoOld()
    {
        static_cast<LayerColor*>(this->getChildByName("mask-cover"))->setVisible(true);

        //第一排。。。。。。。。。。。。。。。。
        std::string termName = "上";
        if(termNo == 2){
            termName = "下";
        }
        resetMaskInfoBy("board_1",
                        StringUtils::format("下载 %d 年级第 %d 页(%s学期)字帖信息",classNum,pageNo,termName.c_str()),
                        true,
                        false
        );

        //第二排
        resetMaskInfoBy("board_2",
                        "下载详细数据文字信息",
                        true,
                        false
        );

        //第三排
        resetMaskInfoBy("board_3",
                        "分析，绘制字帖信息",
                        true,
                        false
        );

        //第四排
        resetMaskInfoBy("board_4",
                        "下载字帖读音",
                        true,
                        false
        );
    }

    void resetMaskInfoBy(std::string boardPrefix,std::string prompt,bool isVisualDown, bool isVisualOk)
    {
          LayerColor *maskColLayer = static_cast<LayerColor*>(this->getChildByName("mask-cover"));

          if(maskColLayer == NULL){
              return;
          }

          if(!maskColLayer->isVisible()){
              return;
          }

          if(maskColLayer == nullptr){
              return;
          }

          //内容提示板
          std::string boardName = boardPrefix+"_txt";
          Label *borderLab = static_cast<Label*>(maskColLayer->getChildByName(boardName));

          //下载图标
          std::string boardDown = boardPrefix+"_logo_down";
          static_cast<Sprite*>(borderLab->getChildByName(boardDown))->setVisible(isVisualDown);

          //OK图标
          std::string boardOk = boardPrefix+"_logo_ok";
          static_cast<Sprite*>(borderLab->getChildByName(boardOk))->setVisible(isVisualOk);

           borderLab->scheduleOnce([=](float dt) {
               borderLab->setString(prompt);
           },0.2f ,"borderLabsetString");
    }

    void initMask()
    {
        //tianHeight = visibleSize.height - topMarin - 5;
        //tianWidth = tianHeight*0.7047;

        //tianWidthCenter = visibleSize.width/2-tianWidth/2;
        //tianHightCenter = visibleSize.height - topMarin + tianHeight;

        //*****************************************
        LayerColor* maskColLayer = LayerColor::create(Color4B(0, 0, 0, 204), this->getChildByName("tie_background")->getBoundingBox().size.width,
                                                                                                    this->getChildByName("tie_background")->getBoundingBox().size.height);
            maskColLayer->setAnchorPoint(Vec2(0, 0));//左下角
            maskColLayer->setPosition(this->getChildByName("tie_background")->getPosition());//));//visibleSize.width*0.70
            maskColLayer->setName("mask-cover");

            float promptX = tianWidth*0.2;

            //第一排。。。。。。。。。。。。。。。。
            std::string termName = "上";
            if(termNo == 2){
                termName = "下";
            }

            initMaskPrompt(maskColLayer,
                           StringUtils::format("下载 %d 年级第 %d 页(%s学期)字帖信息",classNum,pageNo,termName.c_str()),
                           Vec2(promptX, tianHeight*0.70),
                           "board_1"
            );


            //第二排。。。。。。。。。。。。。。。。
            initMaskPrompt(maskColLayer,
                           "下载详细数据文字信息",
                           Vec2(promptX, tianHeight*0.60),
                           "board_2"
            );

            //第三排。。。。。。。。。。。。。。。。
            initMaskPrompt(maskColLayer,
                           "分析，绘制字帖信息",
                           Vec2(promptX, tianHeight*0.50),
                           "board_3"
            );

            //第四排。。。。。。。。。。。。。。。。
            initMaskPrompt(maskColLayer,
                           "下载字帖读音",
                           Vec2(promptX, tianHeight*0.40),
                           "board_4"
            );


            //加入。。。。。
            this->addChild(maskColLayer);
        //}
    }

    void initTestNode(bool isV)
    {
        //setDebugLabel(StringUtils::format("%f,%f",oneP.x,oneP.y));

        auto xPos = tianWidthCenter/2;
        auto tianTpl = Sprite::create("tian.jpg");
        tianTpl->setAnchorPoint(Vec2(0,0));//左下角
        tianTpl->setPosition(Vec2(xPos,tianHightCenter/2));
        oneDemoLabel = tianTpl;

        scoreDrawNode = DrawNode::create();//LayerColor::create(Color4B(255,0,0,125), tianTpl->getContentSize().width, tianTpl->getContentSize().height);
        scoreDrawNode->setAnchorPoint(Vec2(0,0));//左下角
        scoreDrawNode->drawLine(Vec2(0,0), Vec2(100, 100), Color4F(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), 1.0f));

        tianTpl->setScaleX(aCanvasSide/(tianTpl->getContentSize().width));
        tianTpl->setScaleY(aCanvasSide/(tianTpl->getContentSize().height));

        scoreDrawNode->setPosition(Vec2(xPos,tianHightCenter/2));
        scoreDrawNode->setLineWidth(lineWidth);

        tianTpl->setVisible(isV);
        scoreDrawNode->setVisible(isV);

        this->addChild(tianTpl);
        this->addChild(scoreDrawNode);
    }

    void initOffsetCheck()
    {
        TianHelper::offsetPos.x = -1 ;
        TianHelper::offsetPos.y = -1;
        isSingleanchor = true;
        setGifAction(1);
    }

    void checkOffsetCheck()
    {
        if(TianHelper::offsetPos.x == -1 ||
           TianHelper::offsetPos.y == -1
        ){
            isSingleanchor = true;
            setGifAction(1);
        }else{
            setGifAction(3);
        }
    }

    void initGifEvent()
    {
        tianHeight = visibleSize.height - topMarin - 5;
        tianWidth = tianHeight*0.7047;

        tianWidthCenter = visibleSize.width/2-tianWidth/2;
        tianHightCenter = visibleSize.height - topMarin + tianHeight;

        //*****************************************
        promptRedOK = Sprite::create("example_red_ok/1.jpg");
        promptRedOK->setScaleY(tianHeight/promptRedOK->getContentSize().height);
        promptRedOK->setScaleX(tianWidth/promptRedOK->getContentSize().width);
        promptRedOK->setAnchorPoint(Vec2(0,0));//左下角
        promptRedOK->setPosition(Vec2(tianWidthCenter, 15));//));//visibleSize.width*0.70

        auto promptRedOKAni = Animation::create();
        promptRedOKAni->addSpriteFrameWithFile("example_red_ok/2.jpg");
        promptRedOKAni->addSpriteFrameWithFile("example_red_ok/1.jpg");
        promptRedOKAni->setDelayPerUnit(0.3f);
        promptRedOKAni->setRestoreOriginalFrame(true);

        promptRedOK->runAction(RepeatForever::create(Animate::create(promptRedOKAni)));
        this->addChild(promptRedOK);
        promptRedOK->setVisible(false);//255 代表完全不透明，0 代表完全透明。

        //*****************************************
        promptRed = Sprite::create("example_red/1.jpg");
        promptRed->setScaleY(tianHeight/promptRed->getContentSize().height);
        promptRed->setScaleX(tianWidth/promptRed->getContentSize().width);
        promptRed->setAnchorPoint(Vec2(0,0));//左下角
        promptRed->setPosition(Vec2(tianWidthCenter, 15));//));//visibleSize.width*0.70
        promptRed->setName("prompt_red");

        auto exampleChinaOk = Animation::create();
        exampleChinaOk->addSpriteFrameWithFile("example_red/2.jpg");
        exampleChinaOk->addSpriteFrameWithFile("example_red/1.jpg");
        exampleChinaOk->setDelayPerUnit(0.5f);
        exampleChinaOk->setRestoreOriginalFrame(true);

        promptRed->runAction(RepeatForever::create(Animate::create(exampleChinaOk)));
        this->addChild(promptRed);
        promptRed->setVisible(false);//255 代表完全不透明，0 代表完全透明。
    }

    void setGifAction(int step)
    {
        if(step == 1){
            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                setDebugLabel(StringUtils::format("点红"));

                promptRedOK->setVisible(false);
                promptRed->setVisible(true);//255 代表完全不透明，0 代表完全透明。
            });

        }else if(step == 2){
            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=](){
                setDebugLabel(StringUtils::format("红确"));

                promptRed->setVisible(false);//255 代表完全不透明，0 代表完全透明。
                promptRedOK->setVisible(true);
            });

        }else{
            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=](){
                //setDebugLabel(StringUtils::format("红确"));

                promptRed->removeFromParent();//setVisible(false);//255 代表完全不透明，0 代表完全透明。
                promptRedOK->removeFromParent();//setVisible(false);

                promptRed = nullptr;
                promptRedOK = nullptr;
            });

        }
    }

    void removeGifAction(float dlta){
        promptRed->stopActionsByFlags(1);
        promptRed->removeFromParent();
        promptRed = nullptr;
    }

    //初始化の读取页面
    void initDataForDraw()
    {
        HttpClient::getInstance()->setClearRequestPredicate(nullptr);
        HttpClient::getInstance()->setClearResponsePredicate(nullptr);
        HttpClient::getInstance()->clearResponseAndRequestQueue();

        //std::string url("https://wx.ndmooc.com/files/fontdata/word/%E9%86%8B.online.js");
        //downloadFriend(url, "醋");
        //return;

        std::string idxFileUrl = StringUtils::format("https://wx.ndmooc.com/files/fontdata/mapping/tian-mapping-%d-%d-%d.base.js",classNum, termNo,pageNo);

        if(oneWordMappingTianMapping.count(idxFileUrl) == 1){
            setPreparingTianByMask();
            setNotifyLabel(StringUtils::format("%d年%d期%d页索本存", classNum,termNo, pageNo));
            wordMappingTian = oneWordMappingTianMapping[idxFileUrl];

            prepareTianWords();
        }else {
            setNotifyLabel("下载总索文件");
            downloadFriend(idxFileUrl, "总索引文件");
        }
    }

    void onHttpRequestCompleted(HttpClient *sender, HttpResponse *response)
    {

        if (!response)
        {
            return;
        }

        HttpRequest* hRequest = response->getHttpRequest();
        std::string *id = static_cast<std::string*>(hRequest->getUserData());

        int statusCode = response->getResponseCode();
        if (statusCode != 200 ||
            !response->isSucceed()
                ){
            downFailed((*id), hRequest->getUrl());
            setDebugLabel(StringUtils::format("'%s'错因:%s",id->c_str(), response->getErrorBuffer()));

            delete id;
            return;
        }


        downSuccess((*id), hRequest->getUrl(), (*response->getResponseData()));
        delete id;
    }

    void drawTianTianDraw(LayerColor* tianColLayer,int i)
    {
        //0.568
        float wordWidth = tianColLayer->getContentSize().height;
        float posX = wordWidth*0.228;
        float posY = wordWidth*0.317;

        float picWidth = wordWidth*(1-0.228*2);//两边
        float picHeight = wordWidth*(1-(0.347+0.099));//上：0.099 下：0.347

        auto tianTpl = Sprite::create("tian.jpg");
//float beforeW = tianTpl->getContentSize().width;
//float beforeH = tianTpl->getContentSize().height;
        aCanvasSide = picWidth;
        lineWidth = aCanvasSide*0.02;

        tianTpl->setScaleX(picWidth/(tianTpl->getContentSize().width));
        tianTpl->setScaleY(picHeight/(tianTpl->getContentSize().height));
        tianTpl->setAnchorPoint(Vec2(0,0));//左下角
        tianTpl->setPosition(Vec2(posX,posY));
        tianTpl->setName("big_word_tian");

        //增加一个TTF Label
        auto tianLabel =  Label::createWithTTF("。", "fonts/content.ttf",  aCanvasSide);
        //tianLabel->setAnchorPoint(Vec2(0,0));//左下角
        tianLabel->setColor(Color3B::RED);
        tianLabel->setPosition(picWidth/2,picHeight/2);
        tianLabel->setName("big_word_word");

        //->setVisible(false);
        tianTpl->addChild(tianLabel);


        tianColLayer->addChild(tianTpl);

    }

    //左右对联
    void drawLeftRightBottonBanner(LayerColor* tianColLayer,int i)
    {
        auto leftBandLab =  Label::createWithTTF("左\n边\n的\n字", "fonts/content.ttf",  fontSize);
        auto rightBandLab =  Label::createWithTTF("右\n边\n的\n字", "fonts/content.ttf", fontSize);
        auto bottomBandLab = Label::createWithTTF("", "fonts/content.ttf", fontSize);

        leftBandLab->setColor(Color3B::BLACK);
        rightBandLab->setColor(Color3B::BLACK);
        bottomBandLab->setColor(Color3B::BLACK);

        //12*65
        float leftPosX = tianColLayer->getContentSize().height*0.063;
        float leftPosY = tianColLayer->getContentSize().height*0.2258;

        leftBandLab->setAnchorPoint(Vec2(0,0));//左下角
        leftBandLab->setPosition(Vec2(leftPosX,leftPosY));
        tianColLayer->addChild(leftBandLab);
        //oneDemoLabel = leftBandLab;

        //161*65
        float rightPosX = tianColLayer->getContentSize().height*0.8291;
        float rightPosY = tianColLayer->getContentSize().height*0.2258;

        rightBandLab->setAnchorPoint(Vec2(0,0));//左下角
        rightBandLab->setPosition(Vec2(rightPosX,rightPosY));
        tianColLayer->addChild(rightBandLab);
        oneDemoLabel = rightBandLab;

        //27*35
        float bottomPosX = tianColLayer->getContentSize().height*0.1688;
        float bottomPosY = tianColLayer->getContentSize().height*0.205;

        /*
          float tianLCHeight = tianColLayer->getContentSize().height;
          if(tianLCHeight>0){
              setDebugLabel(StringUtils::format("匡高那蛤：%d", tianLCHeight));
          }
  */

        bottomBandLab->setAnchorPoint(Vec2(0,0));//左下角
        bottomBandLab->setPosition(Vec2(bottomPosX,bottomPosY));
        //oneDemoLabel = bottomBandLab;
        tianColLayer->addChild(bottomBandLab);

        leftBanner[i] = leftBandLab;
        rightBanner[i] = rightBandLab;
        bottomBanner[i] = bottomBandLab;
    }

    //画最中间
    void drawTianListTpl(LayerColor* tianColLayer,int i)
    {
        //画田字格
        drawTianTianDraw(tianColLayer, i);

        //画左右对联汉下横幅
        drawLeftRightBottonBanner(tianColLayer, i);
    }

    void drawDetailListPinyinOneSplit(LayerColor* tianLayer,int i,int num){
        float border = (tianLayer->getContentSize().width-(tianLayer->getContentSize().height*num))/num;
        //setDebugLabel(StringUtils::format("分笔个数：%d\tborde:%f", num,border));

        for(int i=0;i<num;i++) {
            float splitX = i * (tianLayer->getContentSize().height+border);

            auto tplDrawNode = DrawNode::create();//LayerColor::create(Color4B(255,0,0,125), tianTpl->getContentSize().width, tianTpl->getContentSize().height);
            tplDrawNode->setAnchorPoint(Vec2(0, 0));//左下角
            tplDrawNode->setPosition(Vec2(splitX, 0));
            tplDrawNode->setTag(i);
            tplDrawNode->setLineWidth(3);//red
            tplDrawNode->drawLine(Vec2(0,0), Vec2(tianLayer->getContentSize().height, tianLayer->getContentSize().height), Color4F(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), 0.3f));
            tplDrawNode->drawLine(Vec2(0,tianLayer->getContentSize().height), Vec2(tianLayer->getContentSize().height,0), Color4F(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), 0.3f));
            tianLayer->addChild(tplDrawNode);
        }
    }

    void drawDetailListPinyinOne(LayerColor* tianLayer, int i)
    {
        //0.663
        float detailInfoPosX = tianLayer->getBoundingBox().size.width*0.0708;
        float detailInfoPosY = tianLayer->getBoundingBox().size.height*0.6593;

        //拼音
        auto detailInfoLab =  Label::createWithTTF("pīn", "fonts/content.ttf",  fontSize*1.2);

        //setDebugLabel(StringUtils::format("白条 x=%f,,y=%f", tianLayer->getContentSize().width,tianLayer->getContentSize().height));

        detailInfoLab->setAnchorPoint(Vec2(0.5,0.5));//左下角
        detailInfoLab->setPosition(Vec2(detailInfoPosX, detailInfoPosY));
        detailInfoLab->setColor(Color3B(237,119,119));

        pinyinBar[i] = detailInfoLab;
        //oneDemoLabel = detailInfoLab;

        tianLayer->addChild(detailInfoLab);

        //高汉上面查白多
        float oneDetailHeight = tianLayer->getContentSize().height*0.2286;
        float oneDetailWidth = tianLayer->getContentSize().width - tianLayer->getContentSize().width/7;

        //宽分 7 个
        float detailInfoSplitPosX = tianLayer->getContentSize().width/7;
        float detailInfoSplitPosY = tianLayer->getContentSize().height*0.53743;

        //分笔
        auto halfColLayer = LayerColor::create(Color4B(0,0,0,0), oneDetailWidth, oneDetailHeight);
        halfColLayer->setAnchorPoint(Vec2(0,0));//左下角
        halfColLayer->setPosition(Vec2(detailInfoSplitPosX,detailInfoSplitPosY));

        stepByStep[i] = halfColLayer;
        drawDetailListPinyinOneSplit(halfColLayer,i,3);

        tianLayer->addChild(halfColLayer);

        /*竖线提示*/
        float lineBarX = tianLayer->getContentSize().width/7-1;
        float lineBarY = tianLayer->getContentSize().height*0.4944;
        float lineBarHeight = tianLayer->getContentSize().height*0.2992;
        auto barLayer = LayerColor::create(Color4B(18,79,2,125), 2 , lineBarHeight);
        barLayer->setAnchorPoint(Vec2(0,0));//左下角
        barLayer->setPosition(Vec2(lineBarX,lineBarY));
        tianLayer->addChild(barLayer);

        //oneDemoLabel = barLayer;
/*
        auto halfColLayer = LayerColor::create(Color4B(255,0,0,125), oneDetailWidth, oneDetailHeight);
        halfColLayer->setAnchorPoint(Vec2(0,0));//左下角
        halfColLayer->setPosition(Vec2(0,detailInfoPosY));
        tianLayer->addChild(halfColLayer);
*/
    }

    void drawDetailListPinyinAndSplit(LayerColor* tianLayer, int i)
    {
        drawDetailListPinyinOne(tianLayer, i);
    }

    void drawDetailListTianByTian(LayerColor* tianLayer, int j)
    {
        //宽分 7 个
        dynamicCanvasSide = tianLayer->getContentSize().width/7;

        //高汉上面查白多
        //float oneDetailHeight = tianLayer->getContentSize().height*0.717;

        //float dynamicCanvasSideDraw = dynamicCanvasSide*0.1;

        for(int i=0;i<7;i++) {
            auto tianTpl = Sprite::create("tian.jpg");
            tianTpl->setScale(dynamicCanvasSide / (tianTpl->getContentSize().width));
            tianTpl->setAnchorPoint(Vec2(0, 0));//左下角
            tianTpl->setPosition(Vec2(i*dynamicCanvasSide, 0));

            tianLayer->addChild(tianTpl);

            auto tplDrawNode = DrawNode::create();//LayerColor::create(Color4B(255,0,0,125), tianTpl->getContentSize().width, tianTpl->getContentSize().height);
            tplDrawNode->setAnchorPoint(Vec2(0,0));//左下角
            //tplDrawNode->setPosition(Vec2(i*dynamicCanvasSide+dynamicCanvasSideDraw,0));
            tplDrawNode->setPosition(Vec2(i*dynamicCanvasSide,0));

            tplDrawNode->drawLine(Vec2(0,0), Vec2(dynamicCanvasSide, dynamicCanvasSide), Color4F(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), 0.3f));
            tplDrawNode->drawLine(Vec2(0,dynamicCanvasSide), Vec2(dynamicCanvasSide, 0), Color4F(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), 0.3f));
            tianLayer->addChild(tplDrawNode);

            if(i == 0){
                dynamicDrawTian[j] = tplDrawNode;//注意 j 是外圈
            }else{
                auto scoreLab =  Label::createWithTTF("打分", "fonts/content.ttf",  fontSize*muTianScale);
                scoreLab->setAnchorPoint(Vec2(0,1));//左下角
                scoreLab->setPosition(Vec2(3,dynamicCanvasSide));
                scoreLab->setName("score-lab");
                scoreLab->setColor(Color3B::RED);

                tplDrawNode->addChild(scoreLab);

                int ii = i-1;
                tplDrawNode->setName(StringUtils::format("tian-bihua-show-tpl-%d-%d",i,j));
                handDrawTian[ii][j] = tplDrawNode;
            }
        }

/*
        auto halfColLayer = LayerColor::create(Color4B(255,0,0,125), oneDetailWidth, oneDetailHeight);
        halfColLayer->setAnchorPoint(Vec2(0,0));//左下角
        halfColLayer->setPosition(Vec2(0,detailInfoPosY));
        tianLayer->addChild(halfColLayer);
*/
    }

    void drawDetailListBar(LayerColor* tianLayer, int i)
    {
        float detailInfoHeight = tianLayer->getContentSize().height*0.188;
        float detailInfoPosY = tianLayer->getContentSize().height - detailInfoHeight;
        float detailInfoPosX = tianLayer->getContentSize().width*0.025;

        //setDebugLabel(StringUtils::format("详细信息高：%f\n开始 Y 高：%f\n右侧白条高：%f", detailInfoHeight,detailInfoPosY,tianLayer->getContentSize().height));

        //int fontSize = 15;
        auto detailInfoLab =  Label::createWithTTF("", "fonts/content.ttf",  fontSize*muTianScale*1.1);
        detailInfoLab->setAnchorPoint(Vec2(0,0));//左下角
        detailInfoLab->setPosition(Vec2(detailInfoPosX,detailInfoPosY));
        detailInfoLab->setColor(Color3B::BLACK);

        generalInfoBanner[i] = detailInfoLab;
        //oneDemoLabel = detailInfoLab;

        tianLayer->addChild(detailInfoLab);
        //指示条

        //下边的隔离栅栏，纯粹是为了好卡
        float lineBarY = tianLayer->getContentSize().height * 0.7926;
        auto halfColLayer = LayerColor::create(Color4B(18,79,2,125), tianLayer->getContentSize().width, 2);
        halfColLayer->setAnchorPoint(Vec2(0,0));//左下角
        halfColLayer->setPosition(Vec2(2,lineBarY));
        tianLayer->addChild(halfColLayer);

    }

    //画右侧
    void drawRightDetailListTian(LayerColor* tianLayer,int i)
    {
        //结构详细信息
        drawDetailListBar(tianLayer, i);

        //拼音汉分笔
        drawDetailListPinyinAndSplit(tianLayer, i);

        //打上七个格子
        drawDetailListTianByTian(tianLayer, i);
    }

    //设置 一个横向行
    void initListTianRow(LayerColor* tianColLayer, int i)
    {
        //0.182
        float wordWidth = tianColLayer->getContentSize().height;
        //0.818
        float tianWidth = tianColLayer->getContentSize().width - wordWidth;

        //auto newCnt = StringUtils::format("例格高宽:%f", wordWidth);
        //setDebugLabel(newCnt);

        //画田字格
        drawTianListTpl(tianColLayer, i);

        //右侧的条
        auto tianLayer = LayerColor::create(Color4B(255,255,255,255), tianWidth, tianColLayer->getContentSize().height);

        tianLayer->setAnchorPoint(Vec2(0,0));//左下角
        tianLayer->setPosition(Vec2(wordWidth,0));

        //画右侧
        drawRightDetailListTian(tianLayer,i);

        tianColLayer->addChild(tianLayer);
    }

    //设置一个色条
    LayerColor* initHale2Tian(int i, Color4B oneColumnColor, float oneUpLayerWidth, float oneUplayerHeight,float oneMargin,std::string name){
        auto tianColLayer = LayerColor::create(oneColumnColor, oneUpLayerWidth, oneUplayerHeight-oneMargin);
        tianColLayer->setAnchorPoint(Vec2(0,0));//左下角
        tianColLayer->setName(name);

        float oneTcl_Y = i*oneUplayerHeight;
        tianColLayer->setPosition(Vec2(0,oneTcl_Y));//铺开

        return tianColLayer;
    }

    //上部绘画
    void initDrawInnerCtx_Up(LayerColor *lc)
    {
        float halfHeight = lc->getContentSize().height/2;//这半边高度

        auto halfColLayer = LayerColor::create(Color4B(0,0,0,0), lc->getContentSize().width, halfHeight);
        halfColLayer->setAnchorPoint(Vec2(0,0));//左下角
        halfColLayer->setPosition(Vec2(0,halfHeight));
        halfColLayer->setName("half_column_layer");
        //halfColLayer->setTag(11);

        /*
        auto debugLayer = LayerColor::create(Color4B(0,255,0,255), lc->getContentSize().width, 1);
        debugLayer->setAnchorPoint(Vec2(0,0));
        debugLayer->setPosition(Vec2(0,0));
        halfColLayer->addChild(debugLayer);
        */

        float oneMargin = halfHeight * 0.015;//格子的间隔

        Color4B singleColor = Color4B(249,220,150, 255);
        Color4B doubleColor = Color4B(160,204,91, 255);
        float oneUpLayerWidth = halfColLayer->getContentSize().width;
        float oneUplayerHeight = halfHeight/3;

        for(int i=0;i<3;i++){
            Color4B  oneColumnColor ;
            if(i%2 == 0){
                oneColumnColor = singleColor;
            }else{
                oneColumnColor = doubleColor;
            }

            auto tianColLayer = initHale2Tian(2-i, oneColumnColor, oneUpLayerWidth, oneUplayerHeight,oneMargin, StringUtils::format("big_column_up_%d",i));
            initListTianRow(tianColLayer, i);
            halfColLayer->addChild(tianColLayer);
            /*--------------
            auto newCnt = StringUtils::format("第%d个のY坐标:%f", i, oneTcl_Y);
            setDebugLabel(newCnt);


            debugLayer = LayerColor::create(Color4B(255,0,0,255), lc->getContentSize().width, 1);
            debugLayer->setAnchorPoint(Vec2(0,0));
            debugLayer->setPosition(Vec2(0,oneTcl_Y));
            halfColLayer->addChild(debugLayer);
            --------------*/
            //tianColLayer->setTag(20+i);
        }

        lc->addChild(halfColLayer);

    }

    void setDebugLabel(std::string cnt)
    {
        CCLOG("setDebugLabel:%s",cnt.c_str());
        return;
        Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=](){
            if(connectBleLabel != nullptr) {
                auto newCnt = StringUtils::format("%s\n%s", cnt.c_str(),connectBleLabel->getString().c_str());

                connectBleLabel->setString(newCnt);
                float disLabY = visibleSize.height - connectBleLabel->getContentSize().height;
                connectBleLabel->setPosition(Vec2(20, disLabY));//visibleSize.width*0.64, 0
            }
        });
    }

    void initPromptLayer(){
        auto visibleSize = Director::getInstance()->getVisibleSize();

        auto promptLayer = LayerColor::create(Color4B(29, 29, 29, 125), visibleSize.width, visibleSize.height);
        promptLayer->setAnchorPoint(Vec2(0,0));
        promptLayer->setPosition(Vec2(visibleSize.width, 0));//));//visibleSize.width*0.70
        //promptLayer->setPosition(Vec2(visibleSize.width*0.5, 0));//));//visibleSize.width*0.70
        promptLayer->setName("promptLayer");

        auto bleLabel = Label::createWithTTF("连接向导:", "fonts/content.ttf", 32);
        bleLabel->setName("bleLabel");
        //bleLabel->setAnchorPoint(Vec2(0,1));
        bleLabel->setPosition(Vec2(visibleSize.width, 150));//, 0
        //bleLabel->getContentSize();getContentSize().height

        //promptLayer->addChild(bleLabel);

        connectBleLabel = Label::createWithTTF("debug info:", "fonts/content.ttf", 24);
        connectBleLabel->setAnchorPoint(Vec2(0,0));
        //connectBleLabel->setHeight(connectBleLabel->getContentSize().height);
        float disLabX = visibleSize.width*0.30/2;
        float disLabY = visibleSize.height - connectBleLabel->getContentSize().height;
        connectBleLabel->setPosition(Vec2(20, disLabY));//visibleSize.width*0.64, 0
        promptLayer->addChild(connectBleLabel,3);

        this->addChild(promptLayer);
        //auto moveTo = MoveTo::create(1, Vec2(visibleSize.width*0.7, 0));
        //promptLayer->runAction(moveTo);
    }

    void drawWordPinList(LayerColor* tianColLayer,float oneDetailWidth,float spliterWords,int i,int j)
    {
        int offset = spliterWords*(i/2);
        float oneWordPosS = i*oneDetailWidth+offset;

        auto tianTpl = Sprite::create("tian.jpg");
        tianTpl->setScale(oneDetailWidth / (tianTpl->getContentSize().width));
        tianTpl->setAnchorPoint(Vec2(0, 0));//左下角
        tianTpl->setPosition(Vec2(oneWordPosS, 0));

        tianColLayer->addChild(tianTpl);


        auto tplDrawNode = DrawNode::create();//LayerColor::create(Color4B(255,0,0,125), tianTpl->getContentSize().width, tianTpl->getContentSize().height);
        tplDrawNode->setAnchorPoint(Vec2(0, 0));//左下角
        tplDrawNode->setPosition(Vec2(oneWordPosS, 0));

        tplDrawNode->setLineWidth(3);//red
        tplDrawNode->drawLine(Vec2(0, 0), Vec2(oneDetailWidth, oneDetailWidth),Color4F(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), 0.3f));
        tplDrawNode->drawLine(Vec2(0, oneDetailWidth), Vec2(oneDetailWidth, 0),Color4F(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), 0.3f));
        tianColLayer->addChild(tplDrawNode);

        auto scoreLab =  Label::createWithTTF("打分", "fonts/content.ttf",  fontSize*muTianScale);
        scoreLab->setAnchorPoint(Vec2(0,1));//左下角
        scoreLab->setPosition(Vec2(3,oneDetailWidth));
        scoreLab->setName("score-lab");
        scoreLab->setColor(Color3B::RED);

        tplDrawNode->addChild(scoreLab);

        wordInWordList[j][i] = tplDrawNode;
    }

    void drawWordPinPinList(LayerColor* tianColLayer,float oneDetailWidth,float spliterWords,int i,int j)
    {
        int offset = spliterWords*(i/2);
        float oneWordPosS = i*oneDetailWidth+offset;

        float pinyinCentX = oneWordPosS+oneDetailWidth/2;
        float pinyinCentY = oneDetailWidth+((oneDetailWidth/3)/2);

/*
        auto tianTpl = LayerColor::create(Color4B(255,0,i*30,255), oneDetailWidth, oneDetailWidth/3);//Sprite::create("tian.jpg");
        //tianTpl->setAnchorPoint(Vec2(0, 0));//左下角
        tianTpl->setPosition(Vec2(pinyinCentX, pinyinCentY));
        //oneDemoLabel = tianTpl;
        tianColLayer->addChild(tianTpl);
*/

        //拼音
        auto detailInfoLab =  Label::createWithTTF("yīn", "fonts/content.ttf",  fontSize*1.2);
        //detailInfoLab->setAnchorPoint(Vec2(0,0));//左下角
        detailInfoLab->setPosition(Vec2(pinyinCentX, pinyinCentY));
        detailInfoLab->setColor(Color3B(237,119,119));

        wordsPinyin[j][i] = detailInfoLab;

        tianColLayer->addChild(detailInfoLab);
    }

    //画格子啦
    void initListPinYinAndWordRow(LayerColor *tianColLayer,int j) {
        //宽分 7 个
        float oneDetailWidth = tianColLayer->getContentSize().width / 8.5;
        float spliterWords =  (tianColLayer->getContentSize().width - oneDetailWidth*8)/3;

        //高汉上面查白多
        //float oneDetailHeight = tianColLayer->getContentSize().height*0.717;
        for (int i = 0; i < 8; i++) {
            drawWordPinPinList(tianColLayer, oneDetailWidth, spliterWords,i,j);//拼音列表
            drawWordPinList(tianColLayer, oneDetailWidth, spliterWords,i,j);//文字列表
        }
    }

    //下部绘画
    void initDrawInnerCtx_Down(LayerColor *lc)
    {
        float halfHeight = lc->getContentSize().height/2;//这半边高度

        auto halfColLayer = LayerColor::create(Color4B(0,0,0,0), lc->getContentSize().width, halfHeight);
        halfColLayer->setAnchorPoint(Vec2(0,0));//左下角
        halfColLayer->setPosition(Vec2(0,10));


        float oneMargin = halfHeight * 0.023;//格子的间隔

        Color4B singleColor = Color4B(255,255,255,255);
        float oneUpLayerWidth = halfColLayer->getContentSize().width;
        float oneUplayerHeight = halfHeight/3;


        for(int i=0;i<3;i++){
            auto tianColLayer = initHale2Tian(2-i, singleColor, oneUpLayerWidth, oneUplayerHeight,oneMargin,"small_column_down");
            initListPinYinAndWordRow(tianColLayer, i);
            halfColLayer->addChild(tianColLayer);

            /*--------------
            auto newCnt = StringUtils::format("第%d个のY坐标:%f", i, oneTcl_Y);
            setDebugLabel(newCnt);


            debugLayer = LayerColor::create(Color4B(255,0,0,255), lc->getContentSize().width, 1);
            debugLayer->setAnchorPoint(Vec2(0,0));
            debugLayer->setPosition(Vec2(0,oneTcl_Y));
            halfColLayer->addChild(debugLayer);
            --------------*/
            //tianColLayer->setTag(20+i);
        }

        lc->addChild(halfColLayer);

    }

    void initPageDemo(LayerColor *lc)
    {
        auto bgSprite = Sprite::create("pagedemo.jpg");
        bgSprite->setScaleX((lc->getContentSize().width)/(bgSprite->getContentSize().width));
        bgSprite->setScaleY((lc->getContentSize().height)/(bgSprite->getContentSize().height));

        bgSprite->setAnchorPoint(Vec2(0,0));
        bgSprite->setPosition(Vec2(0,0));

        lc->addChild(bgSprite);
    }

    void initDrawInnerCtx(LayerColor *lc)
    {
//        initPageDemo(lc);
        initDrawInnerCtx_Up(lc);
        initDrawInnerCtx_Down(lc);
    }

    void initIdMapping()
    {
        //上边の映射
        for(int column=0;column<=handDrawTian.size();column++) {
            for(int row=0;row<handDrawTian[column].size();row++){
                auto oneMapKey = StringUtils::format("tian-bihua-show-tpl-%d-%d", column+1, row);//column-row
                idMappingDrawNode[oneMapKey] = handDrawTian[column][row];
                //setDebugLabel(StringUtils::format("上映射%s",oneMapKey.c_str()));
            }
        }

        //上边の映射
        for(int column=1;column<=8;column++) {
            for(int row=0;row<=2;row++){
                auto oneMapKey = StringUtils::format("cizu_word_%d_%d",row, column);//column-row
                idMappingDrawNode[oneMapKey] = wordInWordList[row][column-1];
                //setDebugLabel(StringUtils::format("下映射%s",oneMapKey.c_str()));
            }
        }
        /*
         ["tian-bihua-show-tpl-1-0","tian-bihua-show-tpl-2-0","tian-bihua-show-tpl-3-0","tian-bihua-show-tpl-4-0",
         "tian-bihua-show-tpl-5-0","tian-bihua-show-tpl-6-0","tian-bihua-show-tpl-1-1","tian-bihua-show-tpl-2-1",
         "tian-bihua-show-tpl-3-1","tian-bihua-show-tpl-4-1","tian-bihua-show-tpl-5-1","tian-bihua-show-tpl-6-1",
         "tian-bihua-show-tpl-1-2","tian-bihua-show-tpl-2-2","tian-bihua-show-tpl-3-2","tian-bihua-show-tpl-4-2",
         "tian-bihua-show-tpl-5-2","tian-bihua-show-tpl-6-2",

         "cizu_word_0_1","cizu_word_1_1","cizu_word_2_1","cizu_word_0_2","cizu_word_1_2","cizu_word_2_2",
         "cizu_word_0_3","cizu_word_1_3","cizu_word_2_3","cizu_word_0_4","cizu_word_1_4","cizu_word_2_4",
         "cizu_word_0_5","cizu_word_1_5","cizu_word_2_5","cizu_word_0_6","cizu_word_1_6","cizu_word_2_6",
         "cizu_word_0_7","cizu_word_1_7","cizu_word_2_7","cizu_word_0_8","cizu_word_1_8","cizu_word_2_8"]};
         * */
    }

    void initTemplateLayers(){
        setNotifyLabel(StringUtils::format("数据正在下载。。"));

        tianHeight = (visibleSize.height - topMarin)*0.93;
        tianWidth = tianHeight*0.7047;

        tianWidthCenter = visibleSize.width/2-tianWidth/2;
        tianHightCenter = (visibleSize.height - topMarin - tianHeight) / 2;

        auto tianLayer = static_cast<LayerColor*>(this->getChildByName("tianLayer"));
        if(tianLayer == nullptr) {
            tianLayer = LayerColor::create(Color4B(255, 255, 255, 250), tianWidth, tianHeight);
            tianLayer->setAnchorPoint(Vec2(0, 0));
            tianLayer->setPosition(Vec2(tianWidthCenter, tianHightCenter));//));//visibleSize.width*0.70
            tianLayer->setName("tianLayer");

            float oneTieBGSize = visibleSize.height - topMarin;

            auto tianBg = Sprite::create("tie_background.png");
            tianBg->setAnchorPoint(Vec2(0, 0));//0.84
            tianBg->setName("tie_background");
            tianBg->setScaleY(oneTieBGSize/tianBg->getContentSize().height);
            tianBg->setScaleX((tianWidth*1.14)/tianBg->getContentSize().width);
            stepTB = 0.04;
            tianBg->setPosition(Vec2(tianWidthCenter-tianWidth*0.11, tianHightCenter-tianHeight*stepTB));
            this->addChild(tianBg);
        }

        initDrawInnerCtx(tianLayer);
        initIdMapping();

        this->addChild(tianLayer);

        //遥控器の填入
        if(this->getChildByName("remoter_menu") == nullptr) {
            auto remoteBg = Sprite::create("remoter_menu.png");
            remoteBg->setAnchorPoint(Vec2(0.5, 1));//0.84
            remoteBg->setName("remoter_menu");
            remoteBg->setScale(0.9);
            remoteBg->setPosition(Vec2(tianWidthCenter / 2, tianHeight+15));
            this->addChild(remoteBg);
        }
    }

    void initTitle(){
        Vec2 origin = Director::getInstance()->getVisibleOrigin();

        /////////////////////////////
        // 2. add a menu item with "X" image, which is clicked to quit the program
        //    you may modify it.

        // add a "close" icon to exit the progress. it's an autorelease object
        auto closeItem = MenuItemImage::create(
                "backNormal.png",
                "backSelected.png",
                CC_CALLBACK_1(HandTianScene::menuCloseCallback, this));
        closeItem->setOpacity(128);
        if (closeItem == nullptr ||
            closeItem->getContentSize().width <= 0 ||
            closeItem->getContentSize().height <= 0)
        {
            Director::getInstance()->popScene();
        }
        else
        {
            float x = origin.x + visibleSize.width - closeItem->getContentSize().width/2;
            float y = origin.y + closeItem->getContentSize().height/2;
            closeItem->setPosition(Vec2(x,y));
        }

        // create menu, it's an autorelease object
        auto menu = Menu::create(closeItem, NULL);
        menu->setPosition(Vec2::ZERO);
        this->addChild(menu);

        /////////////////////////////
        // 3. add your codes below...
        auto item4 = MenuItemFont::create("智慧好字帖", [&](Ref *sender) {
        });

        item4->setFontSizeObj(64);
        item4->setFontName("fonts/content.ttf");
        item4->setName("bandTitle");

        float menuTx = origin.x + visibleSize.width/2;// - closeItem->getContentSize().width/2;
        float menuTyA = origin.y + visibleSize.height/2;//-(item4->getContentSize().height/2);
        float menuTyB = origin.y + visibleSize.height-(item4->getContentSize().height/2);


        displayLabel = Label::createWithTTF("字帖加载", "fonts/content.ttf", 32);
        auto pMenu = MenuItemLabel::create(displayLabel, [&](Ref *sender) {});
        pMenu->setAnchorPoint(Vec2(0,1));
        pMenu->setPosition(Vec2(0,0));

        // add the label as a child to this layer
        //this->addChild(displayLabel, 2);
        auto menuTop = Menu::create(item4, pMenu,  nullptr);
        menuTop->alignItemsHorizontally();
        menuTop->setPosition(Vec2(menuTx,menuTyB));//menuTyA
        menuTop->setName("menuTop");

        this->addChild(menuTop);

        menuTop->runAction(
                EaseIn::create(MoveTo::create(0.7, Vec2(menuTx,menuTyB)), 1)
        );

        topMarin = item4->getContentSize().height;//+(visibleSize.height*0.02);
    }

    void menuCloseCallback(cocos2d::Ref* pSender)
    {
        checkoutGlobal();
        auto scene = HelloWorld::createClassPathChooseScene();
        Director::getInstance()->replaceScene(TransitionFade::create(2.5, scene, Color3B(58,81,73)));
    }

    virtual void setNotifyLabel(std::string cnt) override
    {
        CCLOG("setNotifyLabel:%s",cnt.c_str());

            if(displayLabel != nullptr) {
                displayLabel->setString(cnt);
            }
    }

    void setKeyAct(ControlCode &pressKey) override
    {
        if(pressKey == KEY_MENU)
        {
            if(curClassPageChooser != CLASS_PAGELIST_CHOOSE) {
                initClassJustPageTable();
            }
/*
            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=](){
                initClassTable();
            });
*/
        }

        //如果按返回就退出
        if(pressKey == KEY_RETURN ||
           pressKey == KEY_TV_RETURN
        ) {
            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=](){
                if(curClassPageChooser != NO_CHOOSE) {
                    destoryChooseLayerV2(false);
                }else if(this->getChildByName("confirm_layer") == nullptr){
                    showComfirmLayer();
                }else if(this->getChildByName("confirm_layer") != nullptr) {
                    this->getChildByName("confirm_layer")->removeFromParent();
                }
            });

        }

        if(pressKey == VOLUMN_UP ||
           pressKey == VOLUMN_DOWN
                ) {

            if(pressKey == VOLUMN_UP)
            {
                Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=](){
                    //playingSong("woo.mp3");
                    //showPromptLayer();
                });
            }

            if(pressKey == VOLUMN_DOWN){
                Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=](){
                    hidePromptLayer();
                });
            }

        }

        if(pressKey == PROGRAM_UP ||
           pressKey == PROGRAM_DONW
                ) {
            if(pressKey == PROGRAM_UP) {
                Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                    //clearTianAndInit();
                    curClassPageChooser = CHANGE_PAGE;
                    clearTian();
                    //initTian(true);
                });
            }

            if(pressKey == PROGRAM_DONW) {
                Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                    clearTianAndInit();
                });
            }
        }

        if(pressKey == VOLUMN_MUTE){
            if(this->getChildByName("prompt_red") == nullptr) {
                Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]() {
                    TianHelper::offsetPos.x = -1;
                    TianHelper::offsetPos.y = -1;
                    isSingleanchor = true;

                    initGifEvent();
                    checkOffsetCheck();
                    //BlueToothHelper::notifyTarget->setNotifyLabel("擦除");
                    //destoryChooseLayer();
                });
            }
        }

        if(pressKey == KEY_UP){
            //stepTB += 0.01;
            //this->getChildByName("tie_background")->setPositionY(tianHightCenter-tianHeight*stepTB);

            if(this->getChildByName("confirm_layer") != nullptr){
                changeExitConfirm();
                return;
            }else if(curClassPageChooser == CLASS_PAGELIST_CHOOSE) {
                moveClassPageSelectBarV2(-10);
            }
            /*
            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                if(curClassPageChooser == CLASS_CHOOSE) {
                    prevClassSelectBar();
                    chooseClassCeil();
                }else if(curClassPageChooser == CLASS_PAGELIST_CHOOSE) {
                    //prevClassPageSelectBar();
                    moveClassPageSelectBarV2(-10);
                }

                Vec2 xx = oneDemoLabel->getPosition();
                xx.y += 1;
                oneDemoLabel->setPosition(xx);
                setDebugLabel(StringUtils::format("调整 x=%f,y=%f", xx.x, xx.y));
                setDebugLabel(StringUtils::format("\t上高=%f,上宽=%f",
                                                  oneDemoLabel->getParent()->getContentSize().height,
                                                  oneDemoLabel->getParent()->getContentSize().width));
                setDebugLabel(StringUtils::format("线宽：%f", lineWidth));
            });
            */
        }

        if(pressKey == KEY_DOWN){
            //stepTB -= 0.01;
            //this->getChildByName("tie_background")->setPositionY(tianHightCenter-tianHeight*stepTB);

            if(this->getChildByName("confirm_layer") != nullptr){
                changeExitConfirm();
                return;
            }else if(curClassPageChooser == CLASS_PAGELIST_CHOOSE) {
                //nextClassPageSelectBar();
                moveClassPageSelectBarV2(10);
            }
            /*
            return;
            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                if(curClassPageChooser == CLASS_CHOOSE) {
                    nextClassSelectBar();
                    chooseClassCeil();
                }else if(curClassPageChooser == CLASS_PAGELIST_CHOOSE) {
                    //nextClassPageSelectBar();
                    moveClassPageSelectBarV2(10);
                }


                Vec2 xx = oneDemoLabel->getPosition();;
                xx.y -= 1;
                oneDemoLabel->setPosition(xx);
                setDebugLabel(StringUtils::format("调整 x=%f,y=%f", xx.x, xx.y));
                setDebugLabel(StringUtils::format("\t上高=%f,上宽=%f",
                                                  oneDemoLabel->getParent()->getContentSize().height,
                                                  oneDemoLabel->getParent()->getContentSize().width));
                //});
                setDebugLabel(StringUtils::format("线宽：%f", lineWidth));
            });
*/
        }

        if(pressKey == KEY_LEFT){
            if(this->getChildByName("confirm_layer") != nullptr){
                changeExitConfirm();
                return;
            }else if(curClassPageChooser == NO_CHOOSE) {
                if (HandTianScene::pageNo == 1) {
                    setDebugLabel(StringUtils::format("已经是第1页"));
                    return;
                }

                HandTianScene::pageNo--;
                clearTianAndInit();
            }else if(curClassPageChooser == CLASS_PAGELIST_CHOOSE) {
                moveClassPageSelectBarV2(-1);
            }

        }

        if(pressKey == KEY_RIGHT){
            if(this->getChildByName("confirm_layer") != nullptr){
                changeExitConfirm();
                return;
            }else if(curClassPageChooser == NO_CHOOSE)
            {
                if (HandTianScene::pageNo > getTotalPage()) {
                    setDebugLabel(StringUtils::format("已经是第最后一页"));
                    return;
                }

                HandTianScene::pageNo++;
                clearTianAndInit();
            }else if(curClassPageChooser == CLASS_PAGELIST_CHOOSE) {
                moveClassPageSelectBarV2(1);
            }


/*
            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {

                if(curClassPageChooser == NO_CHOOSE) {
                    if (HandTianScene::pageNo >= classPageMapping[selectedBarPos]) {
                        setDebugLabel(StringUtils::format("已经是第最后一页"));
                        return;
                    }

                    HandTianScene::pageNo++;
                    clearTianAndInit();
                }else if(curClassPageChooser == CLASS_PAGELIST_CHOOSE) {
                    moveClassPageSelectBarV2(1);
                }else  if (curClassPageChooser == CLASS_CHOOSE) {
                    //TODO: 做选择逻辑
                    chooseClassPageListCeil();
                }
            });
*/
/*
                //Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                Vec2 xx = oneDemoLabel->getPosition();
                xx.x += 1;
                oneDemoLabel->setPosition(xx);
                setDebugLabel(StringUtils::format("调整 x=%f,y=%f", xx.x, xx.y));

                setDebugLabel(StringUtils::format("\t上高=%f,上宽=%f",
                                              oneDemoLabel->getParent()->getContentSize().height,
                                              oneDemoLabel->getParent()->getContentSize().width));
            //});
*/
        }

        if(pressKey == KEY_CHOOSE) {
            if(this->getChildByName("confirm_layer") != nullptr){
                if(isLogoutConfirm){
                    BlueToothHelper::notifyTarget->setNotifyLabel("ヾ(￣▽￣)Bye~Bye~");
                    //Director::getInstance()->end()
                    checkoutGlobal();
                    auto scene = HelloWorld::createClassPathChooseScene();
                    Director::getInstance()->replaceScene(TransitionFade::create(2.5, scene, Color3B(58,81,73)));
                }else{
                    this->getChildByName("confirm_layer")->removeFromParent();
                }
            }else if(curClassPageChooser == CLASS_PAGELIST_CHOOSE) {
                chooseClassPageCeilV2();
            }
            return;
            //setGifAction(3);
            //setDebugLabel(StringUtils::format("成功那蛤"));
            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                if (curClassPageChooser == CLASS_CHOOSE) {
                    //TODO: 做选择逻辑
                    chooseClassPageListCeil();
                }else if(curClassPageChooser == CLASS_PAGELIST_CHOOSE)
                {
                    chooseClassPageCeil();
                }
            });
        }
    }
    void changeExitConfirm()
    {
        Sprite *ceS       = static_cast<Sprite *>(this->getChildByName("confirm_layer")->getChildByName("confirm_return_yes"));
        Sprite *ceScancle = static_cast<Sprite *>(this->getChildByName("confirm_layer")->getChildByName("confirm_return_cancel"));

        if(isLogoutConfirm){
            ceS->setVisible(false);
            ceScancle->setVisible(true);
            isLogoutConfirm = false;
        }else{
            ceS->setVisible(true);
            ceScancle->setVisible(false);
            isLogoutConfirm = true;
        }
    }
    void showComfirmLayer()
    {
        auto mastLayer = LayerColor::create(Color4B(88,87,86, 120), visibleSize.width, visibleSize.height);
        mastLayer->setAnchorPoint(Vec2(0, 0));//左下角
        mastLayer->setPosition(Vec2(0, 0));

        mastLayer->setName("confirm_layer");

        auto ceS = Sprite::create("confirm_return_yes.png");
        ceS->setAnchorPoint(Vec2(0.5, 0.5));
        ceS->setVisible(false);
        ceS->setName("confirm_return_yes");
        ceS->setPosition(Vec2(visibleSize.width*0.5, visibleSize.height*0.64));
        mastLayer->addChild(ceS);


        auto ceScancle = Sprite::create("confirm_return_cancel.png");
        ceScancle->setVisible(true);
        ceScancle->setName("confirm_return_cancel");
        ceScancle->setAnchorPoint(Vec2(0.5, 0.5));
        ceScancle->setPosition(Vec2(visibleSize.width*0.5, visibleSize.height*0.64));
        mastLayer->addChild(ceScancle);

        this->addChild(mastLayer);

        isLogoutConfirm = false;
    }

    int getTotalPage()
    {
        int pos = HandTianScene::classNum * 2;
        if (HandTianScene::termNo == 1) {
            pos--;
        }
        ValueMap onePPageS = handPageInfo[std::to_string(pos)].asValueMap();
        int totalPage = onePPageS["totalPage"].asInt();

        return totalPage;
    }

    void focusDrawUpByCanvasName() {
        //TODO:实现 strokesHelper.focusDrawUpByCanvasName(oneWordPos,this, lastDrawCanvasName);
        //getHandWrite(true, true);
        getHandWriteAdapter(true,true);
    }

    //放下一个命令
    virtual void setOneAct(ActCmd &oneCmd) override
    {
        if(oneCmd.act == Pen_Write){
            /*
            //坐标转换
            float mm = oneCmd.x;
            oneCmd.x = 1-oneCmd.y;
            oneCmd.y = mm;
            */
            if(oneCmd.actDetail == PenStatus_Down){
                if(isSingleanchor){
                    TianHelper::offsetPos.x = oneCmd.x;
                    TianHelper::offsetPos.y = oneCmd.y;

                    if(BlueToothHelper::connectDeviceType == 2){
                        TianHelper::offsetPos.x = 0;
                        TianHelper::offsetPos.y = 0;
                    }

                    setGifAction(2);

                    this->scheduleOnce([&](float dt) {
                        setGifAction(3);
                    },2 ,"setGifAction");

                    isSingleanchor = false;
                }else {
                    //penHover->setVisible(false);
                    SimpleAudioEngine::getInstance()->resumeBackgroundMusic();

                    drawingCanvasId = TianHelper::getPosNameByPos(oneCmd.x, oneCmd.y);
                    /*
                    Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]() {
                        if (drawingCanvasId.length() > 0) {
                            //setDebugLabel(StringUtils::format("格中名:%s\n%s", drawingCanvasId.c_str(),idMappingDrawNode[drawingCanvasId]->getName().c_str()));
                            //idMappingDrawNode[drawingCanvasId]->drawCircle(Vec2(0,0), aCanvasSide/2, CC_DEGREES_TO_RADIANS(90), 30, false, Color4F(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), 1.0f));
                        }
                    });
                    */

                    if(drawingCanvasId.length() > 0){
                        //playingSong("pencil.mp3");

                        //配置没加载就退出。。
                        if(wordMappingTian.idMappingGrid.count(drawingCanvasId) == 0){
                            return;
                        }

                        if(lastCanvasId != drawingCanvasId &&
                           lastCanvasId.size() > 0
                                ){
                            focusDrawUpByCanvasName();
                            oneWordPos.clear();
                        }

                        oneStroke.clear();
/*
                        if(wordMappingTian.idMappingGrid.count(drawingCanvasId) == 0){
                            return;
                        }
*/
                        if(oneWordPos.size() == 0 &&
                           drawingCanvasId.length() != 0
                        ){
                            DrawTianOrClean(drawingCanvasId);
                        }
                    }
                    lastCanvasId = drawingCanvasId;

//
//                    if(lastCanvasId != drawingCanvasId){
//                        //TODO: 强制判分
//                        oneStroke.clear();
//                        oneWordPos.clear();
//                    }
                }

            }

            if(oneCmd.actDetail == PenStatus_Move){
                if(drawingCanvasId.length() > 0) {
                    oneStroke.push_back(Vec2(oneCmd.x,oneCmd.y));

                }
            }
            if(oneCmd.actDetail == PenStatus_Up){
                //penHover->setVisible(true);
                /*
                Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]() {
                    //setDebugLabel(StringUtils::format("格抬:%s", lastCanvasId.c_str()));
                });
*/

                if(lastCanvasId.length() > 0){
                    if(oneStroke.size() > 0) {
                        oneWordPos.push_back(oneStroke);
                        appendSIOStrokes();
                    }
                    if (drawUp()) {
                        oneWordPos.clear();
                    }

                    oneStroke.clear();
                }
/*
                if(drawingCanvasId.length() > 0 &&
                   oneStroke.size() > 0
                ){
                    oneWordPos.push_back(oneStroke);

                    if (drawUp()) {
                        oneWordPos.clear();
                    }
                    oneStroke.clear();
                }

                if(lastCanvasId.size()> 0 &&
                   lastCanvasId != drawingCanvasId
                ){
                    //TODO: 强制判分
                    oneStroke.clear();
                    oneWordPos.clear();
                }

                lastCanvasId = drawingCanvasId;
*/
            }
            if(oneCmd.actDetail == PenStatus_Leave){
            }

            if(oneCmd.actDetail == PenStatus_Hover){
            }

            //cmd.append(std::to_string(oneCmd.x)).append(",y=").append(std::to_string(oneCmd.y)).append(",presure=").append(std::to_string(oneCmd.presure));
            //putNotifyLabel(cmd);
        }

        if(oneCmd.act == Pen_Ctl){
            if(oneCmd.actDetail == PenStatus_SAVE){
            }
            if(oneCmd.actDetail == PenStatus_CLEAR){
                drawMuTian();
                uploadSioCtrl("clear");
            }
            if(oneCmd.actDetail == PenStatus_BLUE){
                penColor = Color4F::BLUE;
            }
            if(oneCmd.actDetail == PenStatus_BLACK){
                penColor = Color4F::WHITE;
            }
            if(oneCmd.actDetail == PenStatus_RED){
                penColor = Color4F::RED;
            }
            if(oneCmd.actDetail == PenStatus_PEN_FINE){
            }
            if(oneCmd.actDetail == PenStatus_PEN_MEDIUM){
            }
            if(oneCmd.actDetail == PenStatus_PEN_BOLD){
            }
            if(oneCmd.actDetail == PenStatus_MOUSE_CHOOSE){
            }
            if(oneCmd.actDetail == PenStatus_PEN_CHOOSE){
                Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                    initGifEvent();
                    initOffsetCheck();
                });
            }
            if(oneCmd.actDetail == PenStatus_NEXT){
            }
            if(oneCmd.actDetail == PenStatus_PREV){
            }
        }

    }

    static void ding(){

    }

    bool isFinishCurrentWordByBihua()
    {
        if(drawingCanvasId.length() == 0 ||
           wordMappingTian.idMappingGrid.count(drawingCanvasId) == 0
                ){
            return false;
        }

        std::string &oneWord = wordMappingTian.idMappingGrid[drawingCanvasId].word;
        if(oneWordDetailMapping.count(oneWord) == 0){
            return false;
        }

        if(oneWordPos.size() >= oneWordDetailMapping[oneWord].bishun.bihuaNum){
            return true;
        }else{
            return false;
        }
    }

    bool drawUp()
    {
        bool isNeedClear = false;
        isNeedClear = isFinishCurrentWordByBihua();
        if(isNeedClear){
            //ding();
        }

        //getHandWrite(isNeedClear);
        getHandWriteAdapter(isNeedClear);

        return isNeedClear;
    }

    void getScaleHand(std::vector<Vec2> &handDrawVec,bool isLast)
    {
        if (oneWordPos.size() == 0 ||
            drawingCanvasId.length() == 0 ||
            wordMappingTian.idMappingGrid.count(drawingCanvasId) == 0 ||
            idMappingDrawNode.count(drawingCanvasId) == 0
                )
        {
            return ;
        }

        float beginX = 1;//visibleSize.width;
        float beginY = 1;//visibleSize.height;

        float finishX = 0;
        float finishY = 0;

        for(int i=0 ;i<oneWordPos.size();i++)
        {
            std::vector<Vec2> &oneS = oneWordPos[i];
            for(int j=0;j< oneS.size();j++)
            {
                Vec2 &curP = oneS[j];

                float curX = curP.x;
                float curY = 1-curP.y;

                if (beginX > curX)
                {
                    beginX = curX;
                }

                if (beginY > curY)
                {
                    beginY = curY;
                }

                if (finishX < curX)
                {
                    finishX = curX;
                }

                if (finishY < curY)
                {
                    finishY = curY;
                }
            }
        }

        float wordWidth  = (finishX - beginX)*dynamicCanvasSide;
        float wordHeight = (finishY - beginY)*dynamicCanvasSide;

        std::string& miaoMuIdx = wordMappingTian.idMappingGrid[drawingCanvasId].word;

        if(oneWordDetailMapping.count(miaoMuIdx) == 0){
            return;
        }

        OneWordDetail myWordInfo =  oneWordDetailMapping[miaoMuIdx];

        //计算比率
        //伸缩比例
        float fontMatWidth = myWordInfo.fontSize.width;
        float fontMatHeight = myWordInfo.fontSize.height;

        float scaleRatioWidth = fontMatWidth / wordWidth;
        float scaleRatioHeight = fontMatHeight / wordHeight;

        DrawNode* disPic = idMappingDrawNode[drawingCanvasId];

        float offsetLeft = (dynamicCanvasSide-fontMatWidth)/2;
        float offsetTop = (dynamicCanvasSide-fontMatHeight)/2;

        std::string drawCanvasId = drawingCanvasId;
        if(isLast){
            drawCanvasId = lastCanvasId;
        }

        for(int i=0;i< oneWordPos.size();i++)
        {
            std::vector<Vec2> oneS = oneWordPos[i];

            if(oneS.size() < 2){
                continue;
            }

            for(int j=1;j< oneS.size();j++)
            {
                Vec2 curP = oneS[j];

                float  oneAbsX = (curP.x-beginX);
                float  oneAbsY =((1-curP.y)-beginY);

                float absX = oneAbsX*dynamicCanvasSide*scaleRatioWidth;
                float absY = oneAbsY*dynamicCanvasSide*scaleRatioHeight;

                handDrawVec.push_back(Vec2(absX,absY));
            }
        }
    }

    void getHandWriteOld(bool isNeedClear,bool isLast=false)
    {
        if (oneWordPos.size() == 0 ||
            drawingCanvasId.length() == 0 ||
            wordMappingTian.idMappingGrid.count(drawingCanvasId) == 0 ||
            idMappingDrawNode.count(drawingCanvasId) == 0
                )
        {
            return ;
        }

        bool isForceScore = isNeedClear;

        float beginX = 1;//visibleSize.width;
        float beginY = 1;//visibleSize.height;

        float finishX = 0;
        float finishY = 0;

        for(int i=0 ;i<oneWordPos.size();i++)
        {
            std::vector<Vec2> &oneS = oneWordPos[i];
            for(int j=0;j< oneS.size();j++)
            {
                Vec2 &curP = oneS[j];

                float curX = curP.x;
                float curY = 1-curP.y;

                if (beginX > curX)
                {
                    beginX = curX;
                }

                if (beginY > curY)
                {
                    beginY = curY;
                }

                if (finishX < curX)
                {
                    finishX = curX;
                }

                if (finishY < curY)
                {
                    finishY = curY;
                }
            }
        }

        float wordWidth = (finishX - beginX)*dynamicCanvasSide;
        float wordHeight = (finishY - beginY)*dynamicCanvasSide;

        std::string& miaoMuIdx = wordMappingTian.idMappingGrid[drawingCanvasId].word;

        if(oneWordDetailMapping.count(miaoMuIdx) == 0){
            return;
        }

        OneWordDetail myWordInfo =  oneWordDetailMapping[miaoMuIdx];

        //计算比率
        //伸缩比例
        float fontMatWidth = myWordInfo.fontSize.width;
        float fontMatHeight = myWordInfo.fontSize.height;

        float scaleRatioWidth = fontMatWidth / wordWidth;
        float scaleRatioHeight = fontMatHeight / wordHeight;

        DrawNode* disPic = idMappingDrawNode[drawingCanvasId];

        if(wordMappingTian.idMappingGrid[drawingCanvasId].isShow){
            drawWordToCanvasId(drawingCanvasId, miaoMuIdx);
        }else{
            CLEAR_CANVAS_AND_SCORE(disPic);//disPic->clear();
        }

        float offsetLeft = (dynamicCanvasSide-fontMatWidth)/2;
        float offsetTop = (dynamicCanvasSide-fontMatHeight)/2;

        disPic->setLineWidth(lineWidth);

        std::vector<Vec2> handDrawVec;
        std::string drawCanvasId = drawingCanvasId;
        if(isLast){
            drawCanvasId = lastCanvasId;
        }

        for(int i=0;i< oneWordPos.size();i++)
        {
            std::vector<Vec2> oneS = oneWordPos[i];

            if(oneS.size() < 2){
                continue;
            }

            float lastOneX = (oneS[0].x - beginX)*dynamicCanvasSide*scaleRatioWidth + offsetLeft;
            float lastOneY = ((1-oneS[0].y) - beginY)*dynamicCanvasSide*scaleRatioHeight + offsetTop;

            float oneX = (oneS[1].x - beginX)*dynamicCanvasSide*scaleRatioWidth + offsetLeft;
            float oneY = ((1-oneS[1].y) - beginY)*dynamicCanvasSide*scaleRatioHeight + offsetTop;

            for(int j=1;j< oneS.size();j++)
            {
                Vec2 curP = oneS[j];

                float  oneAbsX = (curP.x-beginX);
                float  oneAbsY =((1-curP.y)-beginY);

                float absX = oneAbsX*dynamicCanvasSide*scaleRatioWidth;
                float absY = oneAbsY*dynamicCanvasSide*scaleRatioHeight;

                float curX = absX + offsetLeft;// * paperWidth) - beginX;
                float curY = absY + offsetTop;// * paperHeight) - beginY;

                handDrawVec.push_back(Vec2(absX,absY));
                Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                    //注意坐标转换。。
                    //disPic->drawLine(Vec2(onePaper2PixX,onePaper2PixY), Vec2(paper2PixX,paper2PixY), Color4F::RED);

                    //disPic->drawLine(Vec2(oneX,oneY), Vec2(curX,curY), Color4F::BLACK);
                    disPic->drawQuadBezier(Vec2(lastOneX, lastOneY), Vec2(oneX, oneY), Vec2(curX, curY), 30, Color4F::BLACK);
                });

                lastOneX = oneX;
                lastOneY = oneY;

                oneX = curX;
                oneY = curY;
            }
        }

        if(isNeedClear){
            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                drawToScoreTest(oneWordDetailDrawCourseCache[miaoMuIdx]);
                mergeToScoreTest(handDrawVec);
            });

            combineAndScore(handDrawVec, isLast);
        }
    }

    void getHandWriteAdapter(bool isNeedClear,bool isLast=false)
    {
        if(isNeedClear){
            getHandWriteOld(isNeedClear, isLast);
        }else{
            getHandWrite(isNeedClear, isLast);
        }
    }

    void getHandWrite(bool isNeedClear,bool isLast=false)
    {
        if (oneWordPos.size() == 0 ||
            drawingCanvasId.length() == 0 ||
            wordMappingTian.idMappingGrid.count(drawingCanvasId) == 0 ||
            idMappingDrawNode.count(drawingCanvasId) == 0
                ){
            return ;
        }

        bool isForceScore = isNeedClear;

        std::string& miaoMuIdx = wordMappingTian.idMappingGrid[drawingCanvasId].word;

        if(oneWordDetailMapping.count(miaoMuIdx) == 0){
            return;
        }

        OneWordDetail myWordInfo =  oneWordDetailMapping[miaoMuIdx];
        DrawNode* disPic = idMappingDrawNode[drawingCanvasId];

        if(wordMappingTian.idMappingGrid[drawingCanvasId].isShow){
            drawWordToCanvasId(drawingCanvasId, miaoMuIdx);
        }else{
            CLEAR_CANVAS_AND_SCORE(disPic);//disPic->clear();
        }

        disPic->setLineWidth(lineWidth);

        std::string drawCanvasId = drawingCanvasId;
        if(isLast){
            drawCanvasId = lastCanvasId;
        }

        PosListDetail oneDetail = TianHelper::getOneDetailByCanvasId(drawCanvasId);
        Size offsetSize = oneDetail.computRatioOffset();//TianHelper::GetOffsetRatioById(drawCanvasId);//GetOffsetById(drawCanvasId, dynamicCanvasSide);

        for(int i=0;i< oneWordPos.size();i++)
        {
            std::vector<Vec2> oneS = oneWordPos[i];

            if(oneS.size() < 2){
                continue;
            }

            float lastPaper2PixX = (((oneS[0].x-TianHelper::offsetPos.x)-oneDetail.leftBottom.x)/offsetSize.width) * dynamicCanvasSide;
            float lastPaper2PixY = ((oneDetail.leftBottom.y-(oneS[0].y-TianHelper::offsetPos.y))/offsetSize.height) *dynamicCanvasSide;

            float onePaper2PixX = (((oneS[1].x-TianHelper::offsetPos.x)-oneDetail.leftBottom.x)/offsetSize.width) * dynamicCanvasSide;
            float onePaper2PixY = ((oneDetail.leftBottom.y-(oneS[1].y-TianHelper::offsetPos.y))/offsetSize.height) *dynamicCanvasSide;

            for(int j=1;j< oneS.size();j++)
            {
                Vec2 curP = oneS[j];

                float xAbsDist = curP.x-oneDetail.leftBottom.x;
                float yAbsDist = oneDetail.leftBottom.y-curP.y;

                float  oneAbsXRadtio = xAbsDist/offsetSize.width;
                float  oneAbsYRadtio = yAbsDist/offsetSize.height;

                float paper2PixX = (((curP.x-TianHelper::offsetPos.x)-oneDetail.leftBottom.x)/offsetSize.width) * dynamicCanvasSide;
                float paper2PixY = ((oneDetail.leftBottom.y-(curP.y-TianHelper::offsetPos.y))/offsetSize.height) *dynamicCanvasSide;

                if(paper2PixX > 0  &&
                   paper2PixY > 0
                        ) {
                    Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]() {
                        //注意坐标转换。。
                        //disPic->drawLine(Vec2(onePaper2PixX, onePaper2PixY),Vec2(paper2PixX, paper2PixY), Color4F::BLACK);
                        disPic->drawQuadBezier(Vec2(lastPaper2PixX, lastPaper2PixY), Vec2(onePaper2PixX, onePaper2PixY), Vec2(paper2PixX, paper2PixY), 50, Color4F::BLACK);
                    });
                }else{

                }

                lastPaper2PixX = onePaper2PixX;
                lastPaper2PixY = onePaper2PixY;

                onePaper2PixX = paper2PixX;
                onePaper2PixY = paper2PixY;
            }
        }

        if(isNeedClear){
            std::vector<Vec2> handDrawVec;

            getScaleHand(handDrawVec, isLast);

            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                drawToScoreTest(oneWordDetailDrawCourseCache[miaoMuIdx]);
                mergeToScoreTest(handDrawVec);
            });

            combineAndScore(handDrawVec, isLast);
        }
    }

    void clearFlagByCanvasId(std::string drawingCanvasId)
    {
            auto oneFlag = idMappingDrawNode[drawingCanvasId]->getChildByName("scoreimg");
            if(oneFlag != nullptr){
                oneFlag->retain();
                oneFlag->removeFromParentAndCleanup(true);
            }
    }

    void DrawTianOrClean(std::string drawingCanvasId)
    {
        //落笔如果没有写入，那么就清除之前的
        //clearOneTian(name);

        if(wordMappingTian.idMappingGrid[drawingCanvasId].isShow) {
            drawWordToCanvasId(drawingCanvasId,wordMappingTian.idMappingGrid[drawingCanvasId].word);
        }else if(idMappingDrawNode.count(drawingCanvasId) > 0){
            CLEAR_CANVAS_AND_SCORE(idMappingDrawNode[drawingCanvasId]);//idMappingDrawNode[drawingCanvasId]->clear();
        }

        clearFlagByCanvasId(drawingCanvasId);

    }

    //盼盼分
    void combineAndScore(std::vector<Vec2> &handDrawVec, bool isLast)
    {
        std::string &oneWord = wordMappingTian.idMappingGrid[drawingCanvasId].word;
        if(oneWordDetailDrawCourseCache.count(oneWord) == 0 ||
           oneWordDetailMapping.count(oneWord) == 0

                ){
            return ;
        }

        WordDetailDrawCourseCache oneWDDC =  oneWordDetailDrawCourseCache[oneWord];
        OneWordDetail oneWD = oneWordDetailMapping[oneWord];

        float inMatchPoint = 0;//匹配点数
        float inFontPoint = oneWD.drawcourse.size();//字体一共多少点
        float handMatchPoint = 0;//手写的匹配率
        float dupNum  = 0;//重复数字


        //---* 测试完好率 *----------------------------------------
        /*
       size_t numVec = oneWD.drawcourse.size();
       int lastOneX = -1;
       int lastOneY = -1;
       for(size_t j=0;j<numVec;j++) {
           int onePosX = std::floor(dynamicCanvasSide * oneWD.drawcourse[j][0]);
           int onePosY = oneWDDC.size()-std::floor(dynamicCanvasSide * oneWD.drawcourse[j][1]);

           bool isDup = false;
           if(lastOneX == onePosX &&
              lastOneY == onePosY
           ){
               isDup = true;
               dupNum++;
           }

           lastOneX = onePosX;
           lastOneY = onePosY;

           if(isDup) continue;

           if(onePosY >= oneWDDC.size() ||
              onePosX >= oneWDDC[onePosY].size()
            ){
               Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                   setDebugLabel(StringUtils::format("超界"));
               });
           }else {
               if (oneWDDC[onePosY][onePosX]) {
                   oneWDDC[onePosY][onePosX] = false;
                   inMatchPoint++;
               }

               handMatchPoint++;
           }
       }
       */

        int lastOneX = -1;
        int lastOneY = -1;

        for(const auto &oneAct : handDrawVec) {
            int intX = std::floor(oneAct.x);
            int intY = std::floor(oneAct.y);

            bool isDup = false;
            if(lastOneX == intX &&
               lastOneY == intY
                    ){
                isDup = true;
                dupNum++;
            }

            lastOneX = intX;
            lastOneY = intY;

            if(isDup) continue;

            if(intY >= oneWDDC.size() ||
               intX >= oneWDDC[intY].size()
                    ){
                Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                    setDebugLabel(StringUtils::format("超界"));
                });
            }else {
                if (oneWDDC[intY][intX]) {
                    oneWDDC[intY][intX] = false;
                    inMatchPoint++;
                }
            }
            handMatchPoint++;
        }

        //inFontPoint = ;

        //匹配的红模
        float perMatFont = 0;
        if (inFontPoint > 0)
        {
            perMatFont = (inMatchPoint / inFontPoint) * 100;
        }

        //匹配的手写
        float handMatFont = 0;
        if (handMatchPoint > 0)
        {
            handMatFont = (inMatchPoint / handMatchPoint) * 100;
        }

        float penTianPrecent = (handMatchPoint/inFontPoint)*100;

        Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
            setDebugLabel(StringUtils::format("模率:%.1f,写率:%.1f,笔数:%.1f", perMatFont, handMatFont, penTianPrecent));
        });

        //console.log("font matching:"+ perMatFont + "%");//红模匹配
        //console.log("hand matching:" + handMatFont + "%",);//手写匹配
        getTheComment(perMatFont, handMatFont,penTianPrecent, isLast);
    }

    /*
     *  @brief 这是评论的方法
     *  @param float 红模率
     *  @param float 手字率
     *  @param float 点占率
     * */
    void getTheComment(float frontPrecent, float handPrecent, float penTianPrecent, bool isLast)
    {
        bool isForceScore = isFinishCurrentWordByBihua();

        std::string picName = "right.png";

        int score = 0;
        /*
         * 分四种情况：
         * 1、缺少笔画，给出提示：缺少笔画，然后根据比率瞎评论一番像真的一样评语，之后大家都做爷酱状
         * 2、写的一团乱，涂成黑疙瘩，胡人のwriting。红模率/手字比率 > 60 就算这种。点占率>50%吧。。
         * 3、笔数一致，但是结构不合理（左小右大/左大右小/上大下小/上小下大），红木率<10，手字率<=50,点占比<20
         *
         * 4、结构合理、大小之一，像爷酱一样口齿伶俐，像巴西佬一样端庄舒容，像导导宝宝一样雨后天空有放晴后の面容。那么以蛤玩儿为标准呢咩。。
         *    本穷 beliving: 红模率>10，手字率>50,点占比>10
         */

        std::string scoreTxt;//the hand-writing of comment of one word

        //situation 1: less than need what the word had strokes.
        if(!isForceScore){
            scoreTxt = "缺少笔画";
            picName = "wrong.png";

            playingSong("wrong.mp3");
        }
        else{//another type situation: Had matched strokes.

            //situation 2: written a mass.
            std::pair<float, float> F_H_Ratio = std::minmax(frontPrecent,handPrecent);

            if ((F_H_Ratio.first/F_H_Ratio.second)> 0.5  &&
                penTianPrecent > 0.5
                    ){
                scoreTxt = "写成一团";
                picName = "wrong.png";
                playingSong("wrong.mp3");
            }else if(frontPrecent < 10 &&
                     handPrecent <= 60 &&
                     penTianPrecent < 20
             ){//situation 3: matched strokes word,but imbanlance structure.
                scoreTxt = "结构要优化";
                score = handPrecent+penTianPrecent;
                playingSong("ding.mp3");
            }else if(frontPrecent > 10 &&
                     handPrecent > 50 &&
                     penTianPrecent > 10
                    ){//situation 4: matched strokes word,have a nice structure ,another word it's brove written miē.
                scoreTxt = "完美书写";
                score = 90;
                playingSong("bling.mp3");
            }else{//some missing mysterious finding.
                score = handPrecent + penTianPrecent;

                if(frontPrecent < 10){
                    scoreTxt += "漏红多，";
                    picName = "wrong.png";
                }

                if(handPrecent < 50){
                    scoreTxt += "结构需优化，";
                    picName = "wrong.png";
                }

                if((F_H_Ratio.first/F_H_Ratio.second)> 0.5){
                    scoreTxt += "写成较乱，";
                    picName = "wrong.png";
                }

                if(scoreTxt.length() > 0){
                    scoreTxt.pop_back();scoreTxt.pop_back();scoreTxt.pop_back();
                }else{
                    //这到底写个了蛤玩儿咩
                    scoreTxt = "继续努力";
                }

                playingSong("wrong.mp3");
            }
        }

        Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
            BlueToothHelper::notifyTarget->setNotifyLabel(scoreTxt);
        });

        std::string drawCanvasId = drawingCanvasId;
        if(isLast){
            drawCanvasId = lastCanvasId;
        }
        //加标记
        if(picName == "wrong.png"){
            setPicByCanvasId(drawCanvasId, picName);

            Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
                static_cast<cocos2d::Label *>(idMappingDrawNode[drawCanvasId]->getChildByName(
                        "score-lab"))->setString(scoreTxt);
            });
        }

        if(scoreTxt.length()>0){
            if(score > 0) {
                static_cast<cocos2d::Label *>(idMappingDrawNode[drawCanvasId]->getChildByName(
                        "score-lab"))->setString(
                        StringUtils::format("%d分", score));
            }else{
                static_cast<cocos2d::Label *>(idMappingDrawNode[drawCanvasId]->getChildByName(
                        "score-lab"))->setString(
                        StringUtils::format("%s", scoreTxt.c_str()));
            }
        }
    }

    void setPicByCanvasId(std::string canvasId, std::string flagName)
    {
        Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
            /* * */
            auto scoreTpl = Sprite::create(flagName);

            scoreTpl->setScale((aCanvasSide*0.5) / (scoreTpl->getContentSize().width));
            scoreTpl->setName("scoreimg");
            scoreTpl->setAnchorPoint(Vec2(0, 0));//左下角
            scoreTpl->setPosition(Vec2(aCanvasSide*0.5, 0));
            //scoreTpl->setGlobalZOrder(10);

            idMappingDrawNode[canvasId]->addChild(scoreTpl);
        });
    }

    void initKeyBoard(){
        auto listener = EventListenerKeyboard::create();
        listener->onKeyPressed = [=](EventKeyboard::KeyCode keyCode, Event* event){
            ControlCode pressKey = ControlCode(keyCode);
            setKeyAct(pressKey);
//        auto promptxx = StringUtils::format("按下键盘：%d", static_cast<int>(keyCode));
//        BlueToothHelper::notifyTarget->setNotifyLabel(promptxx);
        };

        listener->onKeyReleased = [=](EventKeyboard::KeyCode keyCode, Event* event){
//        auto promptxx = StringUtils::format("抬起键盘：%d", static_cast<int>(keyCode));
//        BlueToothHelper::notifyTarget->setNotifyLabel(promptxx);
        };

        _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
    }

    bool prepareTianDetailInfo(const std::vector<char> &cnt)
    {
        std::string jsonRaw( cnt.begin(), cnt.end());

        rapidjson::Document document;
        document.Parse(jsonRaw.c_str());

        int gotErrNum = 0;

        rapidjson::Value::ConstMemberIterator iter = document.FindMember("pageWordsList");
        if(iter != document.MemberEnd()){
            wordMappingTian.pageWordsList = iter->value.GetString();
            setDebugLabel(StringUtils::format("主字列表:%s",wordMappingTian.pageWordsList.c_str()));
        }else{gotErrNum++;}

        if(document.HasMember("wordPhraseList")){
            const rapidjson::Value& childValue = document["wordPhraseList"];
            for(rapidjson::SizeType i = 0; i < childValue.Size(); ++i){
                std::string onePhrase;

                onePhrase = childValue[i].GetString();
                setDebugLabel(StringUtils::format("造词%d组:%s",i, childValue[i].GetString()));

                wordMappingTian.wordPhraseList[i] = onePhrase;
            }
        }else{gotErrNum++;}

        if(document.HasMember("leftBanner")){
            const rapidjson::Value& childValue = document["leftBanner"];
            for(rapidjson::SizeType i = 0; i < childValue.Size(); ++i){
                wordMappingTian.leftBanner[i] = childValue[i].GetString();
                setDebugLabel(StringUtils::format("左对%d组:%s",i, childValue[i].GetString()));
            }
        }else{gotErrNum++;}

        if(document.HasMember("rightBanner")){
            const rapidjson::Value& childValue = document["rightBanner"];
            for(rapidjson::SizeType i = 0; i < childValue.Size(); ++i){
                wordMappingTian.rightBanner[i] = childValue[i].GetString();
                setDebugLabel(StringUtils::format("右对%d组:%s",i, childValue[i].GetString()));
            }
        }else{gotErrNum++;}

        if(document.HasMember("bottomBanner")){
            const rapidjson::Value& childValue = document["bottomBanner"];
            for(rapidjson::SizeType i = 0; i < childValue.Size(); ++i){
                wordMappingTian.bottomBanner[i] = childValue[i].GetString();
                setDebugLabel(StringUtils::format("横批%d组:%s",i, childValue[i].GetString()));
            }
        }else{gotErrNum++;}

        if(document.HasMember("sentence")){
            const rapidjson::Value& childValue = document["sentence"];
            for(rapidjson::SizeType i = 0; i < childValue.Size(); ++i){
                wordMappingTian.sentence[i] = childValue[i].GetString();
                setDebugLabel(StringUtils::format("造句%d组:%s",i, childValue[i].GetString()));
            }
        }else{gotErrNum++;}

        if(document.HasMember("constitute")){
            const rapidjson::Value& childValue = document["constitute"];
            for(rapidjson::SizeType i = 0; i < childValue.Size(); ++i){
                wordMappingTian.constitute[i] = childValue[i].GetString();
                setDebugLabel(StringUtils::format("结构%d组:%s",i, childValue[i].GetString()));
            }
        }else{gotErrNum++;}

        if(document.HasMember("getMapping")) {
            const rapidjson::Value& mappingValue = document["getMapping"];

            for (int i = 0; i < wordMappingTian.GridIdx.size(); i++) {
                //setDebugLabel(StringUtils::format("爬格%d数", i));

                std::string key = wordMappingTian.GridIdx[i];
                if (mappingValue.HasMember(key.c_str())) {
                    const rapidjson::Value& oneWordMappingValue = mappingValue[key.c_str()];

                    bool isShow = false;
                    rapidjson::Value::ConstMemberIterator chileIter = oneWordMappingValue.FindMember("isShowWord");
                    if (chileIter != oneWordMappingValue.MemberEnd()) {
                        isShow = chileIter->value.GetBool();
                    }

                    std::string oneWord;
                    chileIter = oneWordMappingValue.FindMember("word");
                    if (chileIter != oneWordMappingValue.MemberEnd()) {
                        oneWord = chileIter->value.GetString();
                        /*
                        if (isShow) {
                            setDebugLabel(StringUtils::format("%d.%s√显=%s", i, key.c_str(),
                                                              oneWord.c_str()));
                        } else {
                            setDebugLabel(StringUtils::format("%d.%s×隐=%s", i, key.c_str(),
                                                              oneWord.c_str()));
                        }
                        */
                    }

                    wordMappingTian.idMappingGrid[key].word = oneWord;
                    wordMappingTian.idMappingGrid[key].isShow = isShow;
/*
                    //分析出上下城区
                    bool isUpTown = true;
                    int row = std::stoi(key.substr(key.size() - 1, 1));
                    int col = std::stoi(key.substr(key.size() - 3, 1));

                    if (key.find("cizu_word") != std::string::npos) {
                        isUpTown = false;
                        std::swap(row, col);
                    }

                    if (isUpTown) {
                        wordMappingTian.upTownG[row][col].word = oneWord;
                        wordMappingTian.upTownG[row][col].isShow = isShow;
                    } else {
                        wordMappingTian.downTownGrid[row][col].word = oneWord;
                        wordMappingTian.downTownGrid[row][col].isShow = isShow;
                    }
*/
                } else {
                    setDebugLabel(StringUtils::format("%s不含", key.c_str()));
                }
            }
        }else{
            setDebugLabel(StringUtils::format("getMapping Anyong Hasayyo 在沉船上"));
        }

        setDebugLabel(StringUtils::format("全素析毕，错%d", gotErrNum));
        if(gotErrNum == 0){
            return true;
        }else{
            return false;
        }
    }

    void prepareOneWord(std::string oneWord)
    {
        const std::string url = StringUtils::format("https://wx.ndmooc.com/files/fontdata/word/%s.online.js", HttpUtils::UrlEncode(oneWord).c_str());

        if (oneWordDetailMapping.find(oneWord) != oneWordDetailMapping.end()){
            setDebugLabel(StringUtils::format("'%s'字1本存√",oneWord.c_str()));
            setPrepareTianWordsMaskById(oneWord);
            return ;
        }

        downloadFriend(url, oneWord);
    }


    void makeBitmapCacheByWordInfo(OneWordDetail &oneWD,std::string &oneWord)
    {
        int oneWidth = std::ceil(oneWD.fontSize.width);
        int oneHeight = std::ceil(oneWD.fontSize.height);

        WordDetailDrawCourseCache oneWordCache;//宇宙坐标
        WordDetailDrawCourseCache oneWordCacheCocos;//cocos2d 坐标。。

        oneWordCache.resize(oneHeight);
        oneWordCacheCocos.resize(oneHeight);

        for(int row=0;row<oneHeight;row++){
            oneWordCache[row].resize(oneWidth);
            oneWordCacheCocos[row].resize(oneWidth);

            std::fill(oneWordCache[row].begin(), oneWordCache[row].end(), false);
            std::fill(oneWordCacheCocos[row].begin(), oneWordCacheCocos[row].end(), false);
        }

        //-------------------------------
        size_t numVec = oneWD.drawcourse.size();

        for(size_t j=0;j<numVec;j++){
            float onePosX = dynamicCanvasSide * oneWD.drawcourse[j][0];
            float onePosY = dynamicCanvasSide * oneWD.drawcourse[j][1];

            fillDrawCousrCacheByXY(oneWordCache, onePosX, onePosY);
        }

        //旋转坐标
        convertToCocosDrawCache(oneWordCache, oneWordCacheCocos);

        drawToScoreTest(oneWordCacheCocos);
        oneWordDetailDrawCourseCache[oneWord] = oneWordCacheCocos;
    }

    void convertToCocosDrawCache(WordDetailDrawCourseCache &oneWordCache, WordDetailDrawCourseCache &oneWordCacheCocos)
    {
        int cloumnNum = oneWordCache.size();
        if(cloumnNum == 0) return;
        int rowNum = oneWordCache[0].size();

        //旋转坐标
        for(int i=0;i<cloumnNum;i++){
            for(int j=0;j<rowNum;j++) {
                if(oneWordCache[i][j]) {
                    int x = j;
                    int y = cloumnNum-1-i;

                    oneWordCacheCocos[y][x] = true;
                }
            }
        }
    }

    void drawToScoreTest(WordDetailDrawCourseCache oneWordCache)
    {
        if(!scoreDrawNode->isVisible()){
            return;
        }

        scoreDrawNode->clear();

        int cloumnNum = oneWordCache.size();
        int rowNum = oneWordCache[0].size();
        //scoreDrawNode->setLineWidth(lineWidth);

        for(int i=0;i<cloumnNum;i++){
            for(int j=0;j<rowNum;j++) {
                if(oneWordCache[i][j]) {
                    int x = j;
                    int y = i;//cloumnNum-i;

                    scoreDrawNode->drawPoint(Vec2(x, y), 1, Color4F::RED);
                }
            }
        }
    }

    void mergeToScoreTest(const std::vector<Vec2> &handDrawVec){
        //scoreDrawNode->setLineWidth(lineWidth);

        for(const auto &oneHD:handDrawVec){
            scoreDrawNode->drawPoint(oneHD, 2, Color4F::BLUE);
        }
    }

    void fillDrawCousrCacheByXY(WordDetailDrawCourseCache &oneWordCache,float onePosX,float onePosY)
    {
        int midNum = 1;//std::ceil(lineWidth/2.0);

        int intX = std::floor(onePosX);
        int intY = std::floor(onePosY);

        int drawHeight = oneWordCache.size();
        if(drawHeight == 0) return;
        int drawWidth = oneWordCache[0].size();

        oneWordCache[intY][intX] = true;

        for(int j=1;j<=midNum;j++){
            //上
            int ox = intX-j;
            int oy = intY-j;

            ASSERT_AND_ASSIGN(ox,oy,drawWidth,drawHeight,oneWordCache);

            //左
            ox = intX-j;
            oy = intY+j;
            ASSERT_AND_ASSIGN(ox,oy,drawWidth,drawHeight,oneWordCache);

            //右
            ox = intX+j;
            oy = intY+j;
            //ASSERT_AND_ASSIGN(ox,oy,drawWidth,drawHeight,oneWordCache);

            //下
            ox = intX+j;
            oy = intY-j;
            //ASSERT_AND_ASSIGN(ox,oy,drawWidth,drawHeight,oneWordCache);

            /*
        //填充左边
        V2F_C4B_T2F a = {Vec2(pos.x - radius, pos.y - radius), Color4B(color), Tex2F(-1.0, -1.0) };
        V2F_C4B_T2F b = {Vec2(pos.x - radius, pos.y + radius), Color4B(color), Tex2F(-1.0,  1.0) };
        V2F_C4B_T2F c = {Vec2(pos.x + radius, pos.y + radius), Color4B(color), Tex2F( 1.0,  1.0) };
        V2F_C4B_T2F d = {Vec2(pos.x + radius, pos.y - radius), Color4B(color), Tex2F( 1.0, -1.0) };
         */
        }


        return;
    }

    bool prepareOneWordInfo(std::vector<char> cnt, std::string oneWord){
        if (oneWordDetailMapping.find(oneWord) != oneWordDetailMapping.end())
        {
            setDebugLabel(StringUtils::format("'%s'字网入本存√",oneWord.c_str()));

            return false;
        }

        std::string jsonRaw( cnt.begin(), cnt.end());

        setDebugLabel(StringUtils::format("'%s'字详杰森:",oneWord.c_str()));
        OneWordDetail oneWD;

        rapidjson::Document document;
        document.Parse(jsonRaw.c_str());

        int gotErrNum = 0;

        if(document.HasMember("width")){
            oneWD.width = document["width"].GetInt();
            setDebugLabel(StringUtils::format("'%s'宽:%d",oneWord.c_str(),oneWD.width));
        }else{gotErrNum++;}


        if(document.HasMember("height")){
            oneWD.height = document["height"].GetInt();
            setDebugLabel(StringUtils::format("'%s'高:%d",oneWord.c_str(),oneWD.height));
        }else{gotErrNum++;}

        if(document.HasMember("drawcourse")){
            const rapidjson::Value& childValue = document["drawcourse"];
            for(rapidjson::SizeType i = 0; i < childValue.Size(); ++i){
                rapidjson::SizeType onePair = childValue[i].Size();
                if(onePair == 2){
                    std::array<float,2> oneDraw;
                    oneDraw[0] = childValue[i][0].GetDouble();
                    oneDraw[1] = childValue[i][1].GetDouble();

                    oneWD.drawcourse.push_back(oneDraw);
                }else{
                    //setDebugLabel(StringUtils::format("'%s'画第%d不二",oneWord.c_str(),i));
                }
            }

            cocos2d::Size fontSize = cocos2d::Size(0,0);
            cocos2d::Size offsetSize = cocos2d::Size(dynamicCanvasSide,dynamicCanvasSide);

            size_t numVec = oneWD.drawcourse.size();
            for(size_t j=0;j<numVec;j++){
                float onePosX = oneWD.drawcourse[j][0];
                float onePosY = oneWD.drawcourse[j][1];


                if(offsetSize.width > onePosX){
                    offsetSize.width = onePosX;
                }
                if(offsetSize.height > onePosY){
                    offsetSize.height = onePosY;
                }

                if(fontSize.width < onePosX){
                    fontSize.width = onePosX;
                }
                if(fontSize.height < onePosY){
                    fontSize.height = onePosY;
                }
            }

            //裁边
            for(size_t j=0;j<numVec;j++){
                oneWD.drawcourse[j][0] -= offsetSize.width;
                oneWD.drawcourse[j][1] -= offsetSize.height;

                oneWD.drawcourse[j][0] *= muTianScale;
                oneWD.drawcourse[j][1] *= muTianScale;
            }

            fontSize.width  -= offsetSize.width;
            fontSize.height -= offsetSize.height;

            oneWD.fontSize.width = dynamicCanvasSide * fontSize.width * muTianScale;
            oneWD.fontSize.height = dynamicCanvasSide * fontSize.height * muTianScale;


            //制作类似 bitmap の缓存
            makeBitmapCacheByWordInfo(oneWD,oneWord);

        }else{gotErrNum++;}

        if(document.HasMember("pinyin")){
            oneWD.pinyin = document["pinyin"].GetString();
            setDebugLabel(StringUtils::format("'%s'拼音:%s",oneWord.c_str(),oneWD.pinyin.c_str()));
        }else{gotErrNum++;}

        if(document.HasMember("bihua")){
            const rapidjson::Value& childValue = document["bihua"];
            for(rapidjson::SizeType i = 0; i < childValue.Size(); ++i){
                rapidjson::SizeType onePair = childValue[i].Size();
                if(onePair == 1){
                    oneWD.bihua.push_back(childValue[i][0].GetString());
                }else{
                    //setDebugLabel(StringUtils::format("'%s'笔画第%d不一",oneWord.c_str(),i));
                }

            }
        }else{gotErrNum++;}

        if(document.HasMember("bushou")){
            oneWD.bushou = document["bushou"].GetString();
            setDebugLabel(StringUtils::format("'%s'部首:%s",oneWord.c_str(),oneWD.bushou.c_str()));
        }else{gotErrNum++;}

        if(document.HasMember("duyin")){
            oneWD.duyin = document["duyin"].GetString();
            setDebugLabel(StringUtils::format("'%s'读音:%s",oneWord.c_str(),oneWD.duyin.c_str()));
        }else{gotErrNum++;}

        if(document.HasMember("bishun")){
            const rapidjson::Value& bishunValue = document["bishun"];
            Bishun oneBishun;

            if(bishunValue.HasMember("pinyin")){
                oneBishun.pinyin = bishunValue["pinyin"].GetString();
                //setDebugLabel(StringUtils::format("'%s'笔顺.读音:%s",oneWord.c_str(),oneBishun.pinyin.c_str()));
            }else{gotErrNum++;}

            if(bishunValue.HasMember("bihuaNum")){
                oneBishun.bihuaNum = bishunValue["bihuaNum"].GetInt();
                //setDebugLabel(StringUtils::format("'%s'笔顺.笔画:%d",oneWord.c_str(),oneBishun.bihuaNum));
            }else{gotErrNum++;}

            if(bishunValue.HasMember("width")){
                oneBishun.width = bishunValue["width"].GetInt();
                //setDebugLabel(StringUtils::format("'%s'笔顺.宽:%d",oneWord.c_str(),oneBishun.width));
            }else{gotErrNum++;}

            if(bishunValue.HasMember("height")){
                oneBishun.height = bishunValue["height"].GetInt();
                //setDebugLabel(StringUtils::format("'%s'笔顺.高:%d",oneWord.c_str(),oneBishun.height));
            }else{gotErrNum++;}

            if(bishunValue.HasMember("bishun")){
                const rapidjson::Value& innerBSValue = bishunValue["bishun"];
                for(rapidjson::SizeType ibsv = 0; ibsv < innerBSValue.Size(); ++ibsv) {
                    BishunDetail oneBsDetail;

                    if(innerBSValue[ibsv].HasMember("idx")){
                        oneBsDetail.idx = innerBSValue[ibsv]["idx"].GetInt();
                    }else{gotErrNum++;}

                    if(innerBSValue[ibsv].HasMember("name")){
                        oneBsDetail.name = innerBSValue[ibsv]["name"].GetString();
                        //setDebugLabel(StringUtils::format("'%s'笔顺.第%d笔%s",oneWord.c_str(),oneBsDetail.idx,oneBsDetail.name.c_str()));
                    }else{gotErrNum++;}

                    if(innerBSValue[ibsv].HasMember("linejoin")){
                        const rapidjson::Value& lineJoinValue = innerBSValue[ibsv]["linejoin"];
                        for(rapidjson::SizeType ljvI = 0; ljvI < lineJoinValue.Size(); ++ljvI) {
                            if(lineJoinValue[ljvI].HasMember("x") &&
                               lineJoinValue[ljvI].HasMember("y")
                                    ){
                                std::array<float,2> oneLineJoinPos;
                                oneLineJoinPos[0] =lineJoinValue[ljvI]["x"].GetDouble();
                                oneLineJoinPos[1] =lineJoinValue[ljvI]["y"].GetDouble();

                                //setDebugLabel(StringUtils::format("'%s'笔顺.第%d笔,线连%d",oneWord.c_str(),oneBsDetail.idx,ljvI));

                                oneBsDetail.linejoin.push_back(oneLineJoinPos);
                            }
                        }
                    }else{gotErrNum++;}

                    oneBishun.bishun.push_back(oneBsDetail);
                }

            }else{gotErrNum++;}

            oneWD.bishun = oneBishun;
        }else{gotErrNum++;}

        setDebugLabel(StringUtils::format("'%s'析完毕错%d", oneWord.c_str(), gotErrNum));
        if(gotErrNum == 0){
            oneWordDetailMapping[oneWord] = oneWD;
            return true;
        }else{
            return false;
        }
    }

    void prepareTianWords()
    {
        size_t haveWNum = StringUtils::getCharacterCountInUTF8String(wordMappingTian.pageWordsList);
        for(int i=0;i<haveWNum;i++){
            prepareOneWord(Helper::getSubStringOfUTF8String(wordMappingTian.pageWordsList,i,1));

        }

        for(int i=0;i<wordMappingTian.wordPhraseList.size();i++){
            haveWNum = StringUtils::getCharacterCountInUTF8String(wordMappingTian.wordPhraseList[i]);

            for(int j=0;j<haveWNum;j++){
                prepareOneWord(Helper::getSubStringOfUTF8String(wordMappingTian.wordPhraseList[i],j,1));
            }
        }

        if (checkIsPrepareAllWordInfo()) {
            setPrepareTianWordsMaskById("全部下载");

            setDebugLabel(StringUtils::format("全字预美，脱贫"));
            //TODO: 开始绘画字帖
            drawAllToCanvas();
            //autoPageHaha();
        }
    }

    void autoPageHaha(){
        HandTianScene::pageNo++;
        if(HandTianScene::pageNo < 80) {
            clearTianAndInit();
        }
    }

    void showPromptLayer()
    {
        Vec2 promptLayPos = connectBleLabel->getParent()->getPosition();
        //if(promptLayPos.x == visibleSize.width){
        connectBleLabel->getParent()->stopAllActions();
        connectBleLabel->getParent()->runAction(
                MoveTo::create(1, Vec2(visibleSize.width*0.75, 0))
        );
        //}
    }

    void hidePromptLayer()
    {
        if(connectBleLabel == nullptr)
            return;

        Vec2 promptLayPos = connectBleLabel->getParent()->getPosition();
        //if(promptLayPos.x < visibleSize.width){
        connectBleLabel->getParent()->stopAllActions();
        connectBleLabel->getParent()->runAction(
                EaseBounceOut::create(MoveTo::create(0.5, Vec2(visibleSize.width, 0)))
        );
        //}
    }

    std::string checkPageAfterDown(const std::string &idWithPage)
    {
        auto const pos = idWithPage.find_last_of("_");
        if(pos == std::string::npos ||
           pos == 0
        ){
            return idWithPage;
        }

        const auto pageNoStr = idWithPage.substr(pos+1);
        if(pageNoStr.length() == 0){
            return idWithPage;
        }

        std::string ret;

        int pageNNo = std::atoi(pageNoStr.c_str());
        if(pageNNo == HandTianScene::pageNo)
        {
            ret = idWithPage.substr(0, pos);
        }

        return ret;
    }



    //下载成功の回调
    void downSuccess(const std::string &idWithPage,const  std::string &url,const std::vector<char> &cnt)
    {
        std::string id = checkPageAfterDown(idWithPage);
        if(id.length() == 0){
            setDebugLabel("艾玛乙烷咩");
            return;
        }


        long ref = this->getReferenceCount();
        if(ref <= 0){
            setDebugLabel("艾玛药丸咩");
            return;
        }
        hidePromptLayer();

        auto xx = StringUtils::format("√任务：‘%s’下载完成",id.c_str());
        setDebugLabel(xx);

        if(id == "总索引文件"){
                //分析所有索引
                bool s = prepareTianDetailInfo(cnt);
                if(!s){
                    setNotifyLabel(StringUtils::format("tian-mapping-%d-%d-%d.base.js 索引文件损坏",classNum, termNo, pageNo));
                    return;
                }

                setPreparingTianByMask();

                oneWordMappingTianMapping[id] = wordMappingTian;
                prepareTianWords();
        }

        if(id.size() == 3){//一个 UTF 等于3个 bytes.

            setPrepareTianWordsMaskById(id);
            //下载某一个字
            if (!prepareOneWordInfo(cnt, id)) {
                //setNotifyLabel(StringUtils::format("'%s'文件结构解析错误，需要重新", id.c_str()));
                return;
            }

            if (checkIsPrepareAllWordInfo()) {
                setPrepareTianWordsMaskById("全部下载");

                setDebugLabel(StringUtils::format("全字预美，准绘"));
                //TODO: 开始绘画字帖
                drawAllToCanvas();
                //autoPageHaha();
            }
        }

        if(id == "分享二维码"){
            // create texture from data
            do
            {
                Texture2D* texture = nullptr;

                Image img;
                if (false == img.initWithImageData((const unsigned char *)cnt.data(), cnt.size()))
                {
                    break;
                }

                texture = new Texture2D();
                if (false == texture->initWithImage(&img))
                {
                    break;
                }

                auto reCodeS = Sprite::createWithTexture(texture);

                auto oneL = this->getChildByName("tianLayer");
                float qrcodeX = -(reCodeS->getContentSize().width*0.35);
                float qrcodeY = oneL->getContentSize().height*0.15;
                float finishQRCodex = -(this->getChildByName("remoter_menu")->getPosition().x)-23;

                reCodeS->setAnchorPoint(Vec2(0.5, 0));//左下角
                reCodeS->setPosition(Vec2(0,0));
                reCodeS->setName("qrcode_share");

                //==圆角掩膜=====================
                auto mask = Sprite::create("sharecode_mask.png");
                mask->setAnchorPoint(Vec2(0.5, 0));
                mask->setPosition(Vec2(0,0));
                mask->setName("mask");
                mask->setScale(reCodeS->getBoundingBox().size.width/mask->getContentSize().width);



                auto clipNode = ClippingNode::create();
                clipNode->setAlphaThreshold(0.0f);
                clipNode->setName("qrcode_share_clip");
                clipNode->setStencil(mask);
                clipNode->addChild(reCodeS);
                clipNode->setAnchorPoint(Vec2(0.5, 0));
                clipNode->setPosition(Vec2(0,0));


                //oneL->addChild(clipNode);

                auto colorLayer = LayerColor::create(Color4B(111,220,150,0), reCodeS->getBoundingBox().size.width, reCodeS->getBoundingBox().size.height+5);
                colorLayer->setAnchorPoint(Vec2(0.5, 0));
                colorLayer->setPosition(Vec2(qrcodeX,qrcodeY));
                colorLayer->addChild(clipNode);

                auto scanWxPrompt = Sprite::create("scan_wx_prompt.png");
                scanWxPrompt->setAnchorPoint(Vec2(0.5,1));
                scanWxPrompt->setName("scan_wx_prompt");
                scanWxPrompt->setScale((reCodeS->getContentSize().width*0.8)/scanWxPrompt->getContentSize().width);
                scanWxPrompt->setPosition(Vec2(0.5,5));
                colorLayer->addChild(scanWxPrompt);

                oneL->addChild(colorLayer);

                float remoteMenuWidth = (this->getChildByName("remoter_menu")->getBoundingBox().size.width*0.9)/reCodeS->getContentSize().width;

                colorLayer->runAction(Sequence::create(Spawn::create(MoveTo::create(0.2, Vec2(qrcodeX, qrcodeY)),
                                                                     ScaleTo::create(0.2, remoteMenuWidth),
                                                                     nullptr
                                                       ),
                                                       MoveTo::create(0.3, Vec2(finishQRCodex, qrcodeY)),
                                                       nullptr
                                      )
                );

                CC_SAFE_RELEASE(texture);
            } while (0);
        }
    }

    void drawDynamicTianOneCoures(std::string &oneWord,DrawNode *dynamicDrawTian,int i)
    {
        dynamicDrawTian->setLineWidth(lineWidth);

        int pointNum = dynamicDrawCourse[i];//写到哪一点？

        OneWordDetail oneWD = oneWordDetailMapping[oneWord];

        if(pointNum >= oneWD.drawcourse.size()){
            pointNum = 0;
            dynamicDrawCourse[i] = -1;//笔画加1
            dynamicDrawTian->clear();
        }

        int wddc = oneWD.drawcourse.size();
        if(wddc<1){
            return;
        }

        drawOneByStepInBarDrawOne(dynamicDrawTian, oneWD.drawcourse, pointNum,oneWD.fontSize);
        dynamicDrawCourse[i]++;//笔画加1
    }

    void drawDynamicTian(float dlta)
    {
        for(int i=0;i<dynamicDrawTian.size();i++){
            std::string oneWord = wordMappingTian.pageWordsList.substr(i * 3, 3);

            drawDynamicTianOneCoures(oneWord, dynamicDrawTian[i], i);
        }
    }
/*
    //画左侧大黑模板
    void drawLeftBigTian(std::string &oneWord,int i, float nodeSize)
    {
        DrawNode *oneDN = pageWordsList[i];

        oneDN->clear();

        OneWordDetail oneWD = oneWordDetailMapping[oneWord];

        size_t numVec = oneWD.drawcourse.size();
        Vec2 pointsVec[numVec];
        for(size_t j=0;j<numVec;j++){
            float onePosX = nodeSize* oneWD.drawcourse[j][0];
            float onePosY = nodeSize*(1.0-oneWD.drawcourse[j][1]);

            pointsVec[j] = Vec2(onePosX, onePosY);
        }

        oneDN->drawPoints(pointsVec, numVec, lineWidth, Color4F::BLACK);
    }
*/
    void drawLeftBigTianByTTF(std::string oneWord,int i)
    {
        Label* tianTpl = static_cast<Label*>(
                this->getChildByName("tianLayer")->
                            getChildByName("half_column_layer")->
                            getChildByName(StringUtils::format("big_column_up_%d",i))->
                            getChildByName("big_word_tian")->getChildByName("big_word_word")
        );

        tianTpl->setString(oneWord);
    }

    void drawGeneralInfo(std::string &oneWord,int i)
    {
        Label * generalInfoBar = generalInfoBanner[i];
        OneWordDetail oneWD = oneWordDetailMapping[oneWord];

        std::string makeScene = wordMappingTian.sentence[i];
        //14个字x3=
        if(makeScene.length() > 42){
            makeScene.substr(0,42);
        }

        //8画 | 手  | 左右结构 | 造句：伴着眼泪的爱情是最感动人的。
        generalInfoBar->setString(StringUtils::format("%d画 | %s | %s | 造句：%s",oneWD.bishun.bihuaNum,
                                                      oneWD.bushou.c_str(),
                                                      wordMappingTian.constitute[i].c_str(),
                                                      makeScene.c_str()
                                  )
        );
    }

    void drawWordMuBar(DrawNode * tplDrawNode,std::vector<std::array<float,2>> &oneBishunD,cocos2d::Size fontSizeSS,Color4F oneSColor=Color4F::BLACK)
    {
        size_t numVec = oneBishunD.size();
        Vec2 pointsVec[numVec];

        float offsetLeft = (dynamicCanvasSide - fontSizeSS.width) /2;
        float offsetHeight = (dynamicCanvasSide - fontSizeSS.height) /2;

        for(size_t j=0;j<numVec;j++){
            float onePosX = dynamicCanvasSide * oneBishunD[j][0]+offsetLeft;
            float onePosY = dynamicCanvasSide * (1.0-oneBishunD[j][1])-offsetHeight;

            //float onePosXAddOffset = dynamicCanvasSide*oneBishunD[j][0]+offsetLeft;
            //float onePosYAddOffset = dynamicCanvasSide*oneBishunD[j][1]+offsetHeight;

            //onePosX += onePosXAddOffset;
            //onePosY -= onePosYAddOffset;

            pointsVec[j] = Vec2(onePosX, onePosY);
        }

        tplDrawNode->drawPoints(pointsVec, numVec, lineWidth, oneSColor);

        return ;
    }

    void drawOneByStepInBarDrawOne(DrawNode * tplDrawNode,std::vector<std::array<float,2>> &oneBishunD,int pointNum,cocos2d::Size fontSizeSS,Color4F oneSColor=Color4F::BLACK)
    {
        float offsetLeft = (dynamicCanvasSide - fontSizeSS.width) /2;
        float offsetHeight = (dynamicCanvasSide - fontSizeSS.height) /2;


        std::array<float,2> oneBD = oneBishunD[pointNum];

        float onePosX = dynamicCanvasSide * oneBD[0] + offsetLeft;
        float onePosY = dynamicCanvasSide * (1.0-oneBD[1]) - offsetHeight;

        //float onePosXAddOffset = dynamicCanvasSide * oneBD[0]*0.1+offsetLeft;
        //float onePosYAddOffset = dynamicCanvasSide * oneBD[1]*0.1+offsetHeight;

        //onePosX *= 0.9;
        //onePosY *= 0.9;

        //onePosX += onePosXAddOffset;
        //onePosY -= onePosYAddOffset;

        tplDrawNode->drawPoint(Vec2(onePosX,onePosY), lineWidth*muTianScale, oneSColor);
    }

    void drawStepByStepInBarDrawOne(DrawNode * tplDrawNode,int j,std::vector<BishunDetail> &bishun,float SSize,bool isScaleDown)
    {
        for(int z=0;z<=j;z++){
            float lastX=-1;float lastY=-1;
            float lastLastX=-1;float lastLastY=-1;
            //setDebugLabel(StringUtils::format("画%d笔", z));

            for(const auto oneBD_LJ:bishun[z].linejoin){
                float x = oneBD_LJ[0];
                float y = oneBD_LJ[1];

                float onePosX = SSize * x;
                float onePosY = SSize * (1.0-y);



                if(isScaleDown){
                    onePosX = SSize * x*muTianScale;
                    onePosY = SSize * (1.0-y*muTianScale);
                }

                if(lastX >= 0 &&
                   lastY >= 0
                        ) {

                    tplDrawNode->drawLine(Vec2(lastX, lastY), Vec2(onePosX,onePosY),Color4F::BLACK);
                    //tplDrawNode->drawQuadBezier(Vec2(lastLastX,lastLastY),Vec2(lastX, lastY), Vec2(onePosX,onePosY),30,Color4F::BLACK);
                }

                lastLastX = lastX;
                lastLastY = lastY;

                lastX = onePosX;
                lastY = onePosY;
            }
        }
    }

    void drawStepByStepInBar(std::string &oneWord,int i)
    {
        //        Director::getInstance()->getScheduler()->performFunctionInCocosThread( [=]() {
        OneWordDetail oneWD = oneWordDetailMapping[oneWord];
        int num = oneWD.bishun.bihuaNum;

        LayerColor *tianLayer = stepByStep[i];

        tianLayer->removeAllChildren();

        Size lcSize = tianLayer->getContentSize();

        float border = (lcSize.width-(lcSize.height*num))/num;

        float widthOne = lcSize.height;
        bool isScaleDown = false;
        if(border < 0){
            widthOne = lcSize.width/(num+1);
            border = widthOne/num;
            isScaleDown = true;
        }

        //setDebugLabel(StringUtils::format("分笔个数：%d\tborde:%f", num,border));

        for(int j=0;j<num;j++) {
            //setDebugLabel(StringUtils::format("'%s'画%d框，线宽:%f", oneWord.c_str(),j, lineWidth));
            float splitX = j * (widthOne+border);
            if(splitX == 0){
                splitX = 5;
            }

            auto tplDrawNode = DrawNode::create();//LayerColor::create(Color4B(255,0,0,125), tianTpl->getContentSize().width, tianTpl->getContentSize().height);
            tplDrawNode->setAnchorPoint(Vec2(0, 0));//左下角
            tplDrawNode->setPosition(Vec2(splitX, 0));

            if(isScaleDown) {
                tplDrawNode->setLineWidth(lineWidth*0.85);//red
            }else {
                tplDrawNode->setLineWidth(lineWidth);//red
            }

            //画一个框0-N笔
            drawStepByStepInBarDrawOne(tplDrawNode, j, oneWD.bishun.bishun,widthOne,isScaleDown);
            //tplDrawNode->drawLine(Vec2(0,0), Vec2(tianLayer->getContentSize().height, tianLayer->getContentSize().height), Color4F(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), 0.3f));
            //tplDrawNode->drawLine(Vec2(0,tianLayer->getContentSize().height), Vec2(tianLayer->getContentSize().height,0), Color4F(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), 0.3f));

            tianLayer->addChild(tplDrawNode);
        }
    }

    void drawPinyinInfo(std::string &oneWord,int i)
    {
        OneWordDetail oneWD = oneWordDetailMapping[oneWord];

        size_t columnN = wordsPinyin.size();
        for(size_t y=0;y<columnN;y++) {
            //wordsPinyin[Y][X]
            pinyinBar[i]->setString(oneWD.pinyin);
            //Vec2 onePPP = pinyinBar[i]->getPosition();
        }
    }


    void drawPhrasePinyinInfo(std::string &oneWords,int row)
    {
        size_t haveWNum = StringUtils::getCharacterCountInUTF8String(oneWords);
        if(haveWNum != 2){
            return;
        }

        std::string oneWord = Helper::getSubStringOfUTF8String(oneWords,0,1);//.substr(0, 3);
        std::string twoWord = Helper::getSubStringOfUTF8String(oneWords,1,1);//oneWords.substr(3, 3);

        OneWordDetail oneWD = oneWordDetailMapping[oneWord];
        OneWordDetail twoWD = oneWordDetailMapping[twoWord];

        for(int column = 0;column<4; column++)
        {
            int oneColumn = column*2;
            int towColumn = column*2+1;

            wordsPinyin[row][oneColumn]->setString(oneWD.pinyin);
            wordsPinyin[row][towColumn]->setString(twoWD.pinyin);
        }

        /*
            wordsPinyin
            OneWordDetail oneWD = oneWordDetailMapping[oneWord];
            pinyinBar[i]->setString(oneWD.pinyin);
            Vec2 onePPP = pinyinBar[i]->getPosition();
        */
    }

    void drawTianLeftRightBottonDesc(int i)
    {
        std::string leftS; //= wordMappingTian.leftBanner[i];
        std::string rightS;// = wordMappingTian.rightBanner[i];
        std::string bootmS = wordMappingTian.bottomBanner[i];

        size_t haveWNum = StringUtils::getCharacterCountInUTF8String(wordMappingTian.leftBanner[i]);
        for(int i=0;i<haveWNum;i++){
            leftS += Helper::getSubStringOfUTF8String(wordMappingTian.leftBanner[i],i,1);//.substr(i * 3, 3);
            leftS += "\n";
        }

        haveWNum = StringUtils::getCharacterCountInUTF8String(wordMappingTian.rightBanner[i]);
        for(int i=0;i<haveWNum;i++){
            rightS += Helper::getSubStringOfUTF8String(wordMappingTian.rightBanner[i],i,1);//.substr(i * 3, 3);
            rightS += "\n";
        }

        leftBanner[i]->setString(leftS);
        rightBanner[i]->setString(rightS);
        //bottomBanner[i]->setString(bootmS);
    }

    void drawFirstTianDynamic(std::string &oneWord,int i)
    {
        //取消所有已经开始写的定时
        this->unschedule(CC_SCHEDULE_SELECTOR(HandTianScene::drawDynamicTian));

        for(const auto oneDT:dynamicDrawTian){
            oneDT->clear();
        }
        //typedef std::array<std::array<int,2>, 3> DrawNodeArrCourse;
        for(int ii=0;ii<dynamicDrawCourse.size();ii++){
            dynamicDrawCourse[ii] = 0;
        }

        lineWidth = 1.6;
        this->schedule(CC_SCHEDULE_SELECTOR(HandTianScene::drawDynamicTian),0.02f);
    }

    void handDrawTianClear(float delt)
    {
        int rowNum = handDrawTianPos[1];
        int columnNum = handDrawTianPos[0];


        if(rowNum >= handDrawTian[columnNum].size()){
            handDrawTianPos[0]++;//column = 0
            handDrawTianPos[1] = 0;//row + 1

            columnNum = handDrawTianPos[0];
            rowNum = handDrawTianPos[1];
        }

        if(columnNum >= handDrawTian.size()){
            //画红模框
            drawMuTian();

            return;
        }

        //setDebugLabel(StringUtils::format("清%d行%d个除", rowNum,columnNum));
        CLEAR_CANVAS_AND_SCORE(handDrawTian[columnNum][rowNum]);//handDrawTian[columnNum][rowNum]->clear();

        handDrawTianPos[1]++;

        HandTianScene::handDrawTianClear(0.0);//, 0.1f); //在1.0f之后执行，并且只执行一次。
    }

    void drawHandTianClear(){
        for(int zz=0;zz<handDrawTianPos.size();zz++){
            handDrawTianPos[zz] = 0;
        }

        //this->scheduleOnce(CC_SCHEDULE_SELECTOR(HandTianScene::handDrawTianClear), 0.2f); //在1.0f之后执行，并且只执行一次。
        HandTianScene::handDrawTianClear(0.0);
    }

    void drawWordToCanvasId(const std::string & oneCanvasId,const std::string & oneWord)
    {
        //void drawDynamicTianOneCoures(std::string &oneWord,DrawNode *dynamicDrawTian,int i)
        if(idMappingDrawNode.count(oneCanvasId) == 0){
            return;
        }

        DrawNode *oneCanvasNode = idMappingDrawNode[oneCanvasId];
        oneCanvasNode->setLineWidth(lineWidth);
        CLEAR_CANVAS_AND_SCORE(oneCanvasNode);//oneCanvasNode->clear();

        OneWordDetail oneWD = oneWordDetailMapping[oneWord];

        drawWordMuBar(oneCanvasNode,oneWD.drawcourse,oneWD.fontSize,Color4F(0.917, 0.67, 0.682, 0.8));
        //drawWordMuBar_8(oneCanvasNode,oneWD.drawcourse,oneWD.fontSize,Color4F(0.917, 0.67, 0.682, 0.8));
    }

    //画上面の红模
    void drawMuTian()
    {
        for(const auto &oneMapping : wordMappingTian.idMappingGrid){
            std::string oneCanvasId = oneMapping.first;

            DrawTianOrClean(oneCanvasId);

        }
    }

    void drawTianAndWord()
    {
        size_t haveWNum = StringUtils::getCharacterCountInUTF8String(wordMappingTian.pageWordsList);///3;
        if(haveWNum == 3) {
            for (int i = 0; i < haveWNum; i++) {
                std::string oneWord = Helper::getSubStringOfUTF8String(wordMappingTian.pageWordsList,i,1);//.substr(i * 3, 3);
                setDrawAllToCanvasMaskById(oneWord,i,9);

                //画左侧大黑模板
                //drawLeftBigTian(oneWord, i, aCanvasSide);
                drawLeftBigTianByTTF(oneWord, i);

                //画几比几画部首造句
                drawGeneralInfo(oneWord, i);

                //拼音
                drawPinyinInfo(oneWord, i);

                //分笔
                drawStepByStepInBar(oneWord, i);

                //画对联
                drawTianLeftRightBottonDesc(i);

                //首部动态
                drawFirstTianDynamic(oneWord, i);
            }

            //随笔消失
            drawHandTianClear();
        }else{
            setDebugLabel(StringUtils::format("'%s'字数不三",wordMappingTian.pageWordsList.c_str()));
        }

        std::string oneWords;
        for(int i=0;i<wordMappingTian.wordPhraseList.size();i++){
            oneWords = wordMappingTian.wordPhraseList[i];

            int curWordNum = 3+i;
            setDrawAllToCanvasMaskById(oneWords,curWordNum,9);

            //一个字(wordMappingTian.wordPhraseList[i].substr(j * 3, 3));
            //拼音
            drawPhrasePinyinInfo(oneWords, i);//wordsPinyin
        }

        setDrawAllToCanvasMaskById(oneWords,9,9, false,true);

        SioJoinRoom();
        hideMask();
        //showShareCode();

        curClassPageChooser = NO_CHOOSE;
    }

    void showShareCode()
    {
        downloadFriend("https://wx.ndmooc.com/files/fontdata/rcode.jpg?class=%d&term=%d&pageno=%d", "分享二维码");
    }

    //同 js の绘画
    void drawAllToCanvas()
    {
        std::string termName = "上";
        if(termNo == 2){
            termName = "下";
        }

        setNotifyLabel(StringUtils::format("%d年级%s学期(第%d页)",classNum ,termName.c_str(),pageNo));
        drawTianAndWord();

        setDebugLabel("已完成开始书写");

        //this->schedule(CC_SCHEDULE_SELECTOR(HandTianScene::drawDynamicTian), 0.2f);
    }

    bool checkIsPrepareAllWordInfo(){
        bool isReady = true;

        size_t haveWNum = StringUtils::getCharacterCountInUTF8String(wordMappingTian.pageWordsList);//.size()/3;

        for(int i=0;i<haveWNum;i++)
        {
            std::string oneKey = Helper::getSubStringOfUTF8String(wordMappingTian.pageWordsList,i,1);//.substr(i * 3, 3);
            if (oneWordDetailMapping.find(oneKey) == oneWordDetailMapping.end()) {
                isReady = false;
            }
        }

        for(int i=0;i<wordMappingTian.wordPhraseList.size();i++) {
            haveWNum = StringUtils::getCharacterCountInUTF8String(wordMappingTian.wordPhraseList[i]);//.size() / 3;

            for (int j = 0; j < haveWNum; j++)
            {
                std::string oneKey = Helper::getSubStringOfUTF8String(wordMappingTian.wordPhraseList[i],j,1);//.substr(j * 3, 3);
                if (oneWordDetailMapping.find(oneKey) == oneWordDetailMapping.end())
                {
                    isReady = false;
                }
            }
        }


        return isReady;
    }

    //下载失败の回调
    void downFailed(const std::string idWithPage,const std::string url){
        //showPromptLayer();
        long ref = this->getReferenceCount();
        if(ref <= 0){
            setDebugLabel("艾玛药丸咩");
            return;
        }

        auto xx = StringUtils::format("×任务：%s 错误:%s",idWithPage.c_str(),url.c_str());
        setDebugLabel(xx);

        std::string id = checkPageAfterDown(idWithPage);
        if(id.length() == 0){
            setDebugLabel("艾玛乙烷咩");
            return;
        }

        downloadFriend(url, id);
    }

//private:
    Color4F penColor;

    float topMarin;
    float tianHeight;
    float tianWidth;
    float tianHightCenter;
    float tianWidthCenter;

    const int fontSize = 21;
    Node *oneDemoLabel;


    //下载之友
    void downloadFriend(std::string url,std::string id)
    {
        std::string idWithPage = id;
        idWithPage.append(StringUtils::format("_%d", HandTianScene::pageNo));

        //创建Request对象
        auto request = new HttpRequest();
        request->setUserData((void *)new std::string(idWithPage));
        //设置请求网址
        request->setUrl(url);
        //设置请求类型
        request->setRequestType(HttpRequest::Type::GET);
        //设置请求的数据
        //char data[50] = "data";
        //request->setRequestData(data,strlen(data));
        //完整的Request对象已经创建成功了

        request->setResponseCallback(CC_CALLBACK_2(HandTianScene::onHttpRequestCompleted, this));
        //创建HttpClient对象
        auto client = HttpClient::getInstance();//getInstance静态成员函数-单例模式模型
        client->setTimeoutForConnect(10);//当客户端向服务端发送请求超过这个时间，就会返回一个错误信息
        client->setTimeoutForRead(10);//接收数据的读取时间
        client->send(request);
        request->release();//释放请求
    }

    std::string lastCanvasId;
    std::string drawingCanvasId;
    std::map<std::string,WordMappingTian> oneWordMappingTianMapping;

    /*结构表*/
    WordMappingTian wordMappingTian;
    /*字の详细信息买凭*/
    std::map<std::string, OneWordDetail> oneWordDetailMapping;
    /*字のvector缓存*/
    std::map<std::string, WordDetailDrawCourseCache> oneWordDetailDrawCourseCache;

    //记录
    Sprite *promptRed;
    Sprite *promptRedOK;


    void initClassJustPageTable()
    {
        curClassPageChooser = CLASS_PAGELIST_CHOOSE;
        selectedClassPageListBarPos = HandTianScene::pageNo;

        initClassPageLayerV2();
        fillClassListPageV2();
        initClassPagelistSelectBarV2();
    }


    void initClassTable()
    {
        curClassPageChooser = CLASS_CHOOSE;
        //页面层
        auto classPageLayer = LayerColor::create(Color4B(105,105,105, 200), visibleSize.width/4, visibleSize.height);
        classPageLayer->setAnchorPoint(Vec2(0,0.5));
        classPageLayer->setPosition(Vec2((-visibleSize.width/4)+visibleSize.width/8, 0));//visibleSize.width/8
        classPageLayer->setName("classPageLayer");
        //classPageLayer->setVisible(false);
        this->addChild(classPageLayer);


        auto promptLayer = LayerColor::create(Color4B(0, 0, 0, 127), visibleSize.width/8, visibleSize.height);
        promptLayer->setAnchorPoint(Vec2(0,0));
        promptLayer->setPosition(Vec2(0, 0));//));//visibleSize.width*0.70
        promptLayer->setName("classLayer");

        float oneCeilHeight = (visibleSize.height/14);

        initClassSelectBar(promptLayer,visibleSize.height/24);
        initClassCeil(promptLayer, "年级选择",oneCeilHeight*13, 13,visibleSize.height/24);

        for(int i=1;i<13;i++){
            int curClassNum = (13-i-1) / 2 + 1;
            int termNum = (13-i-1) % 2;
            //int tag = curClassNum*10+termNum;

            std::string promptStr;
            std::string termStr;
            if (termNum > 0) {
                termStr = "下";
                promptStr = StringUtils::format("　　　　%s学期", termStr.c_str());
            }else{
                termStr = "上";
                promptStr = StringUtils::format("%d年级　%s学期", curClassNum,termStr.c_str());
            }

            initClassCeil(promptLayer,
                          promptStr,
                          oneCeilHeight*i,
                          i,
                          visibleSize.height/35
            );

        }

        this->addChild(promptLayer);

        setClassSelectBar(13);
    }


    void moveClassPageSelectBarV2(int step)
    {
        Sprite *promptLayer = static_cast<Sprite  *>(this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar"));
        promptLayer->stopAllActions();

        int pos = HandTianScene::classNum * 2;
        if (HandTianScene::termNo == 1) {
            pos--;
        }
        ValueMap onePPageS = handPageInfo[std::to_string(pos)].asValueMap();
        int totalPage = onePPageS["totalPage"].asInt();

        if((selectedClassPageListBarPos+step) >= 1 &&
           (selectedClassPageListBarPos+step) <=  totalPage
                ){
            selectedClassPageListBarPos += step;

            LayerColor *pageLab = static_cast<LayerColor *>(this->getChildByName("classPageLayer")->getChildByTag(selectedClassPageListBarPos));

            // run the sequence and repeat forever.
            this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->runAction(FadeOut::create(0.1f));
            this->scheduleOnce([=](float dt) {
                LayerColor *pageBoard = pageLab; //static_cast<LayerColor *>(this->getChildByName("classPageLayer")->getChildByTag(selectedClassPageListBarPos));
                if(pageBoard != nullptr){
                    Vec2 pos = pageBoard->getPosition();
                    pos.y -= pageBoard->getContentSize().height;
                    this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->setPosition(pos);
                }

                this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->runAction(FadeIn::create(0.0f));

                this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->runAction(
                        RepeatForever::create(Sequence::create(
                                FadeOut::create(0.8f),
                                FadeIn::create(0.2f),
                                nullptr)));

                /*
                    Sequence::create(
                            FadeIn::create(0.1f),
                            RepeatForever::create(Sequence::create(
                                    FadeOut::create(0.8f),
                                    FadeIn::create(0.2f),
                                    nullptr)
                            ),
                            nullptr));
                */
            },0.11f ,"removePageListBar");
        }else{
            Sprite *pageListBar = static_cast<Sprite *>(this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar"));

            Vec2 pos = pageListBar->getPosition();

            //如果当前就是最低，就做个动♂作，然后不♀动
            auto seq1 = Sequence::create(MoveTo::create(0.2, Vec2(pos.x, pos.y+5)),
                                         MoveTo::create(0.1, Vec2(pos.x, pos.y)),
                                         RepeatForever::create(Sequence::create(
                                                 FadeOut::create(0.8f),
                                                 FadeIn::create(0.2f),
                                                 nullptr)),
                                         nullptr
            );

            // run the sequence and repeat forever.
            this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->runAction(seq1);

            this->scheduleOnce([=](float dt) {
                this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->runAction(
                        RepeatForever::create(Sequence::create(
                                FadeOut::create(0.8f),
                                FadeIn::create(0.2f),
                                nullptr)));
            },0.31f ,"up_and_down");
        }
    }

    void moveClassPageSelectBar(int step)
    {
        LayerColor *promptLayer = static_cast<LayerColor *>(this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar"));
        promptLayer->stopAllActions();

        if((selectedClassPageListBarPos+step) < 1 ||
           (selectedClassPageListBarPos+step) >  classPageMapping[selectedBarPos]
                ){
            LayerColor *pageLab = static_cast<LayerColor *>(this->getChildByName("classPageLayer")->getChildByTag(selectedClassPageListBarPos));

            Size PLSize = pageLab->getContentSize();
            PLSize.width *= 1.5;
            PLSize.height *= 1.5;
            promptLayer->changeWidthAndHeight(PLSize.width,PLSize.height);

            Vec2 pos = pageLab->getPosition();
            pos.x -= PLSize.width/2;
            pos.y -= PLSize.height/2;

            //如果当前就是最低，就做个动♂作，然后不♀动
            auto seq1 = Sequence::create(MoveTo::create(0.2, Vec2(pos.x, pos.y+5)),
                                         MoveTo::create(0.1, Vec2(pos.x, pos.y)),
                                         nullptr
            );

            // run the sequence and repeat forever.
            this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->runAction(seq1);
        }else{
            selectedClassPageListBarPos += step;

            LayerColor *pageLab = static_cast<LayerColor *>(this->getChildByName("classPageLayer")->getChildByTag(selectedClassPageListBarPos));

            Size PLSize = pageLab->getContentSize();
            PLSize.width *= 1.5;
            PLSize.height *= 1.5;
            promptLayer->changeWidthAndHeight(PLSize.width,PLSize.height);

            Vec2 pos = pageLab->getPosition();
            pos.x -= PLSize.width/2;
            pos.y -= PLSize.height/2;
            this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->runAction(
                    MoveTo::create(0.2, pos)
            );
        }
    }

    void prevClassPageSelectBar()
    {
        this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->stopAllActions();

        if(selectedClassPageListBarPos <= 10){
            LayerColor *pageLab = static_cast<LayerColor *>(this->getChildByName("classPageLayer")->getChildByTag(selectedClassPageListBarPos));

            Vec2 selectedPos = Vec2(
                    pageLab->getPositionX()-pageLab->getContentSize().width/2,
                    pageLab->getPositionY()-pageLab->getContentSize().height/3
            );

            //如果当前就是最低，就做个动♂作，然后不♀动
            auto seq1 = Sequence::create(MoveTo::create(0.2, Vec2(selectedPos.x, selectedPos.y+5)),
                                         MoveTo::create(0.1, Vec2(selectedPos.x, selectedPos.y)),
                                         nullptr
            );

            // run the sequence and repeat forever.
            this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->runAction(seq1);
        }else{
            selectedClassPageListBarPos -= 10;

            LayerColor *pageLab = static_cast<LayerColor *>(this->getChildByName("classPageLayer")->getChildByTag(selectedClassPageListBarPos));
            Vec2 selectedPos = Vec2(
                    pageLab->getPositionX()-pageLab->getContentSize().width/2,
                    pageLab->getPositionY()-pageLab->getContentSize().height/3
            );

            this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->runAction(
                    MoveTo::create(0.2, selectedPos)
            );
        }
    }

    void nextClassPageSelectBar()
    {
        this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->stopAllActions();

        int totalPageNum = classPageMapping[selectedBarPos];

        if((totalPageNum - selectedClassPageListBarPos) < 10){
            LayerColor *pageLab = static_cast<LayerColor *>(this->getChildByName("classPageLayer")->getChildByTag(selectedClassPageListBarPos));

            Vec2 selectedPos = Vec2(
                    pageLab->getPositionX()-pageLab->getContentSize().width/2,
                    pageLab->getPositionY()-pageLab->getContentSize().height/3
            );

            //如果当前就是最低，就做个动♂作，然后不♀动
            auto seq1 = Sequence::create(MoveTo::create(0.2, Vec2(selectedPos.x, selectedPos.y+5)),
                                         MoveTo::create(0.1, Vec2(selectedPos.x, selectedPos.y)),
                                         nullptr
            );

            // run the sequence and repeat forever.
            this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->runAction(seq1);
        }else{
            selectedClassPageListBarPos += 10;

            LayerColor *pageLab = static_cast<LayerColor *>(this->getChildByName("classPageLayer")->getChildByTag(selectedClassPageListBarPos));
            Vec2 selectedPos = Vec2(
                    pageLab->getPositionX()-pageLab->getContentSize().width/2,
                    pageLab->getPositionY()-pageLab->getContentSize().height/3
            );

            this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar")->runAction(
                    MoveTo::create(0.2, selectedPos)
            );
        }
    }

    void prevClassSelectBar()
    {
        this->getChildByName("classLayer")->getChildByName("select_bar")->stopAllActions();

        if(selectedBarPos >= 12){
            selectedBarPos = 12;
            Vec2 selectedPos = this->getChildByName("classLayer")->getChildByTag(selectedBarPos)->getPosition();
            selectedPos.x = 0;
            //如果当前就是最低，就做个动♂作，然后不♀动
            auto seq1 = Sequence::create(MoveTo::create(0.2, Vec2(selectedPos.x, selectedPos.y-5)),
                                         MoveTo::create(0.1, Vec2(selectedPos.x, selectedPos.y)),
                                         nullptr
            );

            this->getChildByName("classLayer")->getChildByName("select_bar")->runAction(seq1);
        }else{
            selectedBarPos++;

            Vec2 selectedPos = this->getChildByName("classLayer")->getChildByTag(selectedBarPos)->getPosition();

            selectedPos.x = 0;
            this->getChildByName("classLayer")->getChildByName("select_bar")->runAction(
                    MoveTo::create(0.2, selectedPos)
            );
        }
    }

    void nextClassSelectBar()
    {
        this->getChildByName("classLayer")->getChildByName("select_bar")->stopAllActions();

        if(selectedBarPos <= 1){
            selectedBarPos = 1;
            Vec2 selectedPos = this->getChildByName("classLayer")->getChildByTag(selectedBarPos)->getPosition();
            selectedPos.x = 0;
            //如果当前就是最低，就做个动♂作，然后不♀动
            auto seq1 = Sequence::create(MoveTo::create(0.2, Vec2(selectedPos.x, selectedPos.y+5)),
                                         MoveTo::create(0.1, Vec2(selectedPos.x, selectedPos.y)),
                                         nullptr
            );

            // run the sequence and repeat forever.
            this->getChildByName("classLayer")->getChildByName("select_bar")->runAction(seq1);
        }else{
            selectedBarPos--;

            Vec2 selectedPos = this->getChildByName("classLayer")->getChildByTag(selectedBarPos)->getPosition();

            selectedPos.x = 0;
            this->getChildByName("classLayer")->getChildByName("select_bar")->runAction(
                    MoveTo::create(0.2, selectedPos)
            );
        }

    }
    void chooseClassPageCeilV2()
    {
        curClassPageChooser = NO_CHOOSE;
        selectedClassPageBarPos = 1;

        destoryChooseLayerV2(true);
    }
    void chooseClassPageCeil()
    {
        curClassPageChooser = CLASS_PAGE_CHOOSE;
        selectedClassPageBarPos = 1;

        destoryChooseLayer();
    }
    void destoryChooseLayerV2(bool isJump){
        if(isJump) {
            if (selectedClassPageListBarPos == 0) {
                return;
            }

            storePageInfo(selectedClassPageListBarPos);
            clearTianAndInit();
        }else {
            this->getChildByName("classPageLayer")->runAction(Sequence::create(
                    EaseBackOut::create(MoveTo::create(0.6f, Vec2((-visibleSize.width / 4), 0))),
                    CallFunc::create([=]() {
                        this->getChildByName("classPageLayer")->stopAllActions();
                        this->getChildByName("classPageLayer")->removeFromParent();

                        curClassPageChooser = NO_CHOOSE;
                    }), nullptr));
        }
    }

    void storePageInfo(int selectedClassPageListBarPos)
    {
        HandTianScene::pageNo = selectedClassPageListBarPos;

        int pos = HandTianScene::classNum * 2;
        if (HandTianScene::termNo == 1) {
            pos--;
        }

        int pageNooo = HandTianScene::pageNo;
        ValueMap onePPageS = handPageInfo[std::to_string(pos)].asValueMap();
        onePPageS["curPage"] = Value(pageNooo);
        handPageInfo[std::to_string(pos)] = Value(onePPageS);

        handPageInfo["curPage"] = Value(pageNooo);
        std::string writablePath = FileUtils::getInstance()->getWritablePath();
        std::string fullPath = writablePath + CLASS_DATA_INFO_PATH;
        //FileUtils::getInstance()->removeFile(fullPath);
        if (FileUtils::getInstance()->writeValueMapToFile(handPageInfo,
                                                          fullPath.c_str())) {
            setDebugLabel("翻页存储成功√ ");
        } else {
            setDebugLabel("翻页存储失败× ");
        }

    }

    void destoryChooseLayer(){

        auto classPageLayerSeq = Sequence::create(MoveTo::create(0.1f, Vec2((-visibleSize.width/4), 0)),nullptr);
        auto classLayerSeq = Sequence::create(DelayTime::create(0.1f),MoveTo::create(0.1f, Vec2((-visibleSize.width/4), 0)),nullptr);

        this->getChildByName("classPageLayer")->runAction(classPageLayerSeq);
        this->getChildByName("classLayer")->runAction(classLayerSeq);

        this->scheduleOnce([&](float dt) {
            this->getChildByName("classPageLayer")->stopAllActions();
            this->getChildByName("classLayer")->stopAllActions();

            this->getChildByName("classPageLayer")->removeFromParent();
            this->getChildByName("classLayer")->removeFromParent();

            curClassPageChooser = NO_CHOOSE;
            chooseClassPageToDraw();


        },0.3f ,"removeClassLayer");
    }
    void chooseClassPageToDraw()
    {
        curClassPageChooser = NO_CHOOSE;

        if(selectedBarPos == 0 ||
           selectedClassPageListBarPos == 0
                ){
            return;
        }

        int curClassNum = (13-selectedBarPos-1) / 2 + 1;//年级

        int termNum = (13-selectedBarPos-1) % 2;//
        termNum++;

        int pageNo = selectedClassPageListBarPos;


        HandTianScene::classNum = curClassNum;
        HandTianScene::pageNo = pageNo;
        HandTianScene::termNo = termNum;

        clearTianAndInit();
    }

    void initClassPageTable()
    {
        LayerColor *promptLayer = static_cast<LayerColor *>(this->getChildByName("classPageLayer"));

        if(promptLayer == nullptr){
            return;
        }
        promptLayer->removeAllChildren();

        setDebugLabel(StringUtils::format("initClassPageTable-removeAllChildren"));
        initClassPageSelectBar();
        setDebugLabel(StringUtils::format("initClassPageTable-initClassPageSelectBar"));
        fillClassPage(promptLayer);

        //this->addChild(promptLayer);

        promptLayer->runAction(MoveTo::create(0.5, Vec2(visibleSize.width/8,0)));
    }

    void initClassPageSelectBar()
    {
        LayerColor *promptLayer = static_cast<LayerColor *>(this->getChildByName("classPageLayer"));

        auto colorLayer = LayerColor::create(Color4B(249,220,150,200), promptLayer->getContentSize().width, promptLayer->getContentSize().height/10);
        colorLayer->setAnchorPoint(Vec2(0,0));
        colorLayer->setName("select_page_bar");
        colorLayer->setPosition(Vec2(0,0));
        colorLayer->setVisible(false);
        promptLayer->addChild(colorLayer);
    }


    void fillClassPage(LayerColor *promptLayer)
    {
        setDebugLabel(StringUtils::format("selectedBarPos %d", selectedBarPos));

        int totalPageNum = classPageMapping[selectedBarPos];
        setDebugLabel(StringUtils::format("fillClassPage %d", totalPageNum));


        if(totalPageNum == 0){
            //TODO: 出一个 coming soon の 提示
            Label* classListLab = Label::createWithTTF(StringUtils::format("没算准o(╥﹏╥)o"), "fonts/content.ttf", visibleSize.height/30);
            classListLab->setAnchorPoint(Vec2(0.5,0));
            classListLab->setPosition(Vec2(promptLayer->getContentSize().width/2, promptLayer->getContentSize().height/0.7));//visibleSize.width*0.64, 0
            classListLab->setTag(0);
            promptLayer->addChild(classListLab);

            curClassPageChooser = CLASS_CHOOSE;
            return;
        }

        int beginPage = (selectedClassPageListBarPos-1)*10+1;

        float oneCeilHeight = (visibleSize.height/10);

        for(int i=0;i<10;i++){
            int tag = beginPage+i;
            std::string title = StringUtils::format("%d 页",tag);
            setDebugLabel(StringUtils::format("%d 页",tag));

            initClassPageCeil(
                    promptLayer,
                    title,
                    oneCeilHeight*i,
                    tag,
                    visibleSize.height/25
            );
        }
    }


    void initClassPageCeil(LayerColor *promptLayer,std::string title,float ceilY,int tag,float fontS)
    {
        Label* classListLab = Label::createWithTTF(title, "fonts/content.ttf", fontS);
        classListLab->setAnchorPoint(Vec2(0.5,0));
        classListLab->setPosition(Vec2(promptLayer->getContentSize().width/2, ceilY));//visibleSize.width*0.64, 0
        classListLab->setTag(tag);

        promptLayer->addChild(classListLab);
    }

    void chooseClassPageSelectBar()
    {
        LayerColor *promptLayer = static_cast<LayerColor *>(this->getChildByName("classPageLayer")->getChildByName("select_page_bar"));

        Label *pageLab = static_cast<Label *>(this->getChildByName("classPageLayer")->getChildByTag(selectedClassPageBarPos));
        setDebugLabel(StringUtils::format("tag:%d", selectedClassPageBarPos));

        promptLayer->setPosition(Vec2(0,pageLab->getPositionY()-pageLab->getContentSize().height/3));
        promptLayer->changeHeight(pageLab->getContentSize().height*1.5);
        promptLayer->setVisible(true);
    }
    void chooseClassPageListCeil()
    {
        curClassPageChooser = CLASS_PAGELIST_CHOOSE;
        selectedClassPageListBarPos = 1;
        chooseClassPagelistSelectBar();
    }


    void chooseClassCeil()
    {
        /*
        LayerColor *promptLayer = static_cast<LayerColor *>(this->getChildByName("classPageLayer"));
        if(!promptLayer->isVisible()) {
            promptLayer->setVisible(true);
        }*/
        //this->getChildByName("classLayer")->getChildByName("select_bar")->stopAllActions();
        if(selectedBarPos == 13){
            Vec2 selectedPos = this->getChildByName("classLayer")->getChildByTag(selectedBarPos)->getPosition();
            selectedPos.x = 0;
            //如果当前就是最低，就做个动♂作，然后不♀动
            auto seq1 = Sequence::create(MoveTo::create(0.2, Vec2(selectedPos.x, selectedPos.y+5)),
                                         MoveTo::create(0.1, Vec2(selectedPos.x, selectedPos.y)),
                                         nullptr
            );

            // run the sequence and repeat forever.
            this->getChildByName("classLayer")->getChildByName("select_bar")->runAction(seq1);
        }
        initClassPageListTable();
    }

    void initClassPageListTable()
    {
        LayerColor *promptLayer = static_cast<LayerColor *>(this->getChildByName("classPageLayer"));
        promptLayer->stopAllActions();
        promptLayer->removeAllChildren();

        initClassPagelistSelectBar();
        fillClassListPage(promptLayer);

        promptLayer->runAction(MoveTo::create(0.2, Vec2(visibleSize.width/8,0)));
    }

    void chooseClassPagelistSelectBar()
    {
        LayerColor *promptLayer = static_cast<LayerColor *>(this->getChildByName("classPageLayer")->getChildByName("select_pagelist_bar"));

        Label *pageLab = static_cast<Label *>(this->getChildByName("classPageLayer")->getChildByTag(selectedClassPageListBarPos));
        setDebugLabel(StringUtils::format("tag:%d", selectedClassPageListBarPos));

        promptLayer->setPosition(Vec2(pageLab->getPositionX()-pageLab->getContentSize().width/2,
                                      pageLab->getPositionY()-pageLab->getContentSize().height/3
        ));

        Size PLSize = pageLab->getContentSize();
        PLSize.width *= 1.5;
        PLSize.height *= 1.5;
        promptLayer->changeWidthAndHeight(PLSize.width,PLSize.height);

        promptLayer->setVisible(true);
    }

    void initClassPagelistSelectBar()
    {
        LayerColor *promptLayer = static_cast<LayerColor *>(this->getChildByName("classPageLayer"));

        int totalPageNum = classPageMapping[selectedBarPos];
        int batchPageB = totalPageNum / 10;
        float oneCeilHeight = (visibleSize.height/14);
        float offsetHeight = (14 - batchPageB)*oneCeilHeight;

        auto colorLayer = LayerColor::create(Color4B(249,220,150, 200), promptLayer->getContentSize().width, oneCeilHeight);
        colorLayer->setAnchorPoint(Vec2(0.5,0.5));
        colorLayer->setName("select_pagelist_bar");
        colorLayer->setPosition(Vec2(0,offsetHeight));
        colorLayer->setVisible(false);
        promptLayer->addChild(colorLayer);
    }

    void initClassPageLayerV2()
    {
        curClassPageChooser = CLASS_PAGELIST_CHOOSE;
        //页面层
        auto classPageLayer = LayerColor::create(Color4B(07,47,104,140), visibleSize.width/4, visibleSize.height);
        classPageLayer->setAnchorPoint(Vec2(0,0.5));
        classPageLayer->setPosition(Vec2(-visibleSize.width/4, 0.0f));//visibleSize.width/8
        classPageLayer->setName("classPageLayer");

        classPageLayer->runAction(MoveTo::create(0.3f, Vec2(0.0f,0.0f)));

        this->addChild(classPageLayer);
    }

    void initClassPagelistSelectBarV2()
    {
        auto colorLayer = Sprite::create("pointer_yellow.png");
        colorLayer->setAnchorPoint(Vec2(0.5,0.5));
        colorLayer->setName("select_pagelist_bar");
        colorLayer->setPosition(Vec2(0,0));

        colorLayer->runAction(RepeatForever::create(Sequence::create(
                FadeOut::create(0.8f),
                FadeIn::create(0.2f),
                nullptr)
                              )
        );
        //colorLayer->setVisible(false);

        LayerColor *promptLayer = static_cast<LayerColor *>(this->getChildByName("classPageLayer"));

        Label *pageBoard = static_cast<Label *>(this->getChildByName("classPageLayer")->getChildByTag(HandTianScene::pageNo));
        if(pageBoard != nullptr){
            Vec2 pos = pageBoard->getPosition();
            pos.y -= pageBoard->getContentSize().height;

            colorLayer->setPosition(pos);
        }

        promptLayer->addChild(colorLayer);
    }

    void initClassPageListOneCeilTitleV2(LayerColor *promptLayer,float ceilY,float oneCeilHeight,ValueMap &onePPageS,int thumbPos)
    {
        auto colorLayer = LayerColor::create(Color4B(83,129,193, 125), promptLayer->getContentSize().width*0.8, oneCeilHeight);
        colorLayer->setAnchorPoint(Vec2(0.0f,0.0f));
        colorLayer->setName("class_page_list_layer");
        colorLayer->setPosition(Vec2(promptLayer->getContentSize().width*0.1,ceilY));

        promptLayer->addChild(colorLayer);

        //==== 书籍 ============
        std::string thumbSuffix = "detail_"+fileNameThumb[thumbPos];
        auto spriteBook = Sprite::create(thumbSuffix);
        spriteBook->setAnchorPoint(Vec2(0, 0));//左下角
        spriteBook->setPosition(Vec2(0, 0));
        spriteBook->setScale(colorLayer->getContentSize().width*0.53/spriteBook->getContentSize().width);
        colorLayer->addChild(spriteBook);

        //==== 文字提示 ==================
        std::string promptText = StringUtils::format("已练习了%d页",onePPageS["writtenPage"].asInt());
        if(onePPageS["writtenPage"].asInt() == 0){
            promptText = "写一页试试吧";
        }

        Label* classListLab = Label::createWithTTF(promptText, "fonts/content.ttf", 28);
        classListLab->setAnchorPoint(Vec2(0,0));
        classListLab->setPosition(Vec2(colorLayer->getContentSize().width*0.47, colorLayer->getContentSize().height*0.45));//visibleSize.width*0.64, 0
        classListLab->setName("class_page_list_prompt");
        colorLayer->addChild(classListLab);

        if(onePPageS["writtenPage"].asInt() > 0) {
            //加几分条
            addScoreBoardV2(colorLayer, onePPageS, classListLab->getContentSize().width);
        }
    }

    void initClassPageListOneCeilV2(LayerColor *promptLayer,std::string title, float ceilX,float ceilY,int tag,float fontS)
    {
        Label* classListLab = Label::createWithTTF(title, "fonts/content.ttf", fontS);
        classListLab->setAnchorPoint(Vec2(0.5,0.5));
        classListLab->setPosition(Vec2(ceilX, ceilY));//visibleSize.width*0.64, 0
        classListLab->setTag(tag);
        promptLayer->addChild(classListLab);
    }

    void addScoreBoardV2(LayerColor *colorLayer,ValueMap &onePPageS,int boardWidth)
    {
        float wp = onePPageS["writtenPage"].asFloat();
        float tp = onePPageS["totalPage"].asFloat();
        float wPrecent = wp / tp;
        //float wPrecent = 20 / tp;


        auto backgroundColorLayer = LayerColor::create(Color4B::WHITE, boardWidth, 5);
        backgroundColorLayer->setAnchorPoint(Vec2(0,0));
        backgroundColorLayer->setPosition(Vec2(colorLayer->getContentSize().width*0.47,colorLayer->getContentSize().height*0.35));
        colorLayer->addChild(backgroundColorLayer);

        //colorbar
        float colorBarWidth = colorLayer->getContentSize().width*wPrecent;
        auto frontColorLayer = LayerColor::create(Color4B(0,150,244,255), colorBarWidth, 5);
        frontColorLayer->setAnchorPoint(Vec2(0,0));
        frontColorLayer->setPosition(Vec2(colorLayer->getContentSize().width*0.47,colorLayer->getContentSize().height*0.35));
        colorLayer->addChild(frontColorLayer);
    }
    void fillClassListPageV2()
    {
        LayerColor *promptLayer = static_cast<LayerColor *>(this->getChildByName("classPageLayer"));

        int pos = HandTianScene::classNum * 2;
        if (HandTianScene::termNo == 1) {
            pos--;
        }

        ValueMap onePPageS = handPageInfo[std::to_string(pos)].asValueMap();

        int totalPageNum = onePPageS["totalPage"].asInt();
        float oneCeilHeight = (visibleSize.height/14);

        int batchPageB = std::ceil((float)totalPageNum / 10.0f);
        float offsetHeight = (14 - batchPageB)*oneCeilHeight-oneCeilHeight*4;

        int oneCileWidth = promptLayer->getContentSize().width/11;

        initClassPageListOneCeilTitleV2(
                promptLayer,
                promptLayer->getContentSize().height-oneCeilHeight*3,
                oneCeilHeight*2,
                onePPageS,
                (pos-1)
        );

        for(int i=0;i<batchPageB;i++){
            for(int j=1;j<=10;j++) {
                int curPage = i*10+j;
                float ceilX = oneCileWidth*j;
                float fontS = visibleSize.height/35;
                if(curPage > 99){
                    fontS = visibleSize.height/50;
                }

                std::string title = StringUtils::format("%d",curPage);

                if(curPage>=totalPageNum){
                    break;
                }

                float ceilY = offsetHeight+oneCeilHeight*(batchPageB-i);
                initClassPageListOneCeilV2(
                        promptLayer,
                        title,
                        ceilX,
                        ceilY,
                        curPage,
                        fontS
                );
            }
        }
    }


    void fillClassListPage(LayerColor *promptLayer)
    {
        int curTag = selectedBarPos;
        int totalPageNum = classPageMapping[curTag];
        float oneCeilHeight = (visibleSize.height/16);

        if(totalPageNum == 0){
            //TODO: 出一个 coming soon の 提示
            initClassPageListOneCeil(
                    promptLayer,
                    "字帖未上线",
                    promptLayer->getContentSize().width/2,
                    promptLayer->getContentSize().height-oneCeilHeight,
                    0,
                    visibleSize.height/25
            );

            return;
        }

        int batchPageB = totalPageNum / 10;
        float offsetHeight = (16 - batchPageB)*oneCeilHeight-oneCeilHeight*2;

        int oneCileWidth = promptLayer->getContentSize().width/11;


        initClassPageListOneCeil(
                promptLayer,
                "选择页数",
                promptLayer->getContentSize().width/2,
                promptLayer->getContentSize().height-oneCeilHeight,
                0,
                visibleSize.height/30
        );

        for(int i=0;i<batchPageB;i++){
            for(int j=1;j<=10;j++) {
                int curPage = i*10+j;
                float ceilX = oneCileWidth*j;
                float fontS = visibleSize.height/35;
                if(curPage > 99){
                    fontS = visibleSize.height/50;
                }

                std::string title = StringUtils::format("%d",curPage);

                if(curPage>totalPageNum){
                    break;
                }

                float ceilY = offsetHeight+oneCeilHeight*(batchPageB-i);
                initClassPageListOneCeil(
                        promptLayer,
                        title,
                        ceilX,
                        ceilY,
                        curPage,
                        fontS
                );
            }
        }
        /*
        for(int i=0;i<batchPageB;i++){
            int beginPage = (batchPageB-1-i)*10+1;
            int endPage = (batchPageB-1-i)*10+10;
            int tag = batchPageB-i;
            std::string title = StringUtils::format("%d页~%d页",beginPage,endPage);

            initClassPageListCeil(
                    promptLayer,
                    title,
                    offsetHeight+oneCeilHeight*i,
                    tag,
                    visibleSize.height/30
            );
        }
       */
    }


    void initClassPageListOneCeil(LayerColor *promptLayer,std::string title, float ceilX,float ceilY,int tag,float fontS)
    {
        Label* classListLab = Label::createWithTTF(title, "fonts/content.ttf", fontS);
        classListLab->setAnchorPoint(Vec2(0.5,0.5));
        classListLab->setPosition(Vec2(ceilX, ceilY));//visibleSize.width*0.64, 0
        classListLab->setTag(tag);
        promptLayer->addChild(classListLab);
    }


    void initClassPageListCeil(LayerColor *promptLayer,std::string title,float ceilY,int tag,float fontS)
    {
        Label* classListLab = Label::createWithTTF(title, "fonts/content.ttf", fontS);
        classListLab->setAnchorPoint(Vec2(0.5,0));
        classListLab->setPosition(Vec2(promptLayer->getContentSize().width/2, ceilY));//visibleSize.width*0.64, 0
        classListLab->setTag(tag);
        promptLayer->addChild(classListLab);
    }

    void setClassSelectBar(float selectTag)
    {
        selectedBarPos = selectTag;

        Vec2 pos = this->getChildByName("classLayer")->getChildByTag(selectTag)->getPosition();

        this->getChildByName("classLayer")->getChildByName("select_bar")->setPosition(Vec2(0,pos.y));
    }

    void initClassSelectBar(LayerColor *promptLayer, float oneCeilHeight)
    {
        auto colorLayer = LayerColor::create(Color4B(249,220,150, 200), promptLayer->getContentSize().width, oneCeilHeight);
        colorLayer->setAnchorPoint(Vec2(0,0));
        colorLayer->setName("select_bar");
        colorLayer->setPosition(Vec2(0,0));
        promptLayer->addChild(colorLayer);
    }

    void appendSIOStrokes(){
        std::lock_guard<std::mutex> guard(SIOStreamMutex);

        if(sioClientIsConnected){
            uploadSioWordPos();
        }else {
            oneSIOWordPos.push_back(oneStroke);
        }

    }

    void uploadSioCtrl(const char *ctrl)
    {
        SocketIOHelper::getInstant()->emit("write_ctrl", StringUtils::format("[[\"ctrl\"],[\"%s\"]]\r\n",ctrl));
    }

    void uploadSioWordPos()
    {
        std::string streamCnt="[[\"stream\"],";

        for(const auto &oneStroke:oneSIOWordPos){
            std::string oneStreamCnt;

            for(const auto &oneVec:oneStroke) {
                float oneX = oneVec.x-TianHelper::offsetPos.x;
                float oneY = oneVec.y-TianHelper::offsetPos.y;

                oneStreamCnt += StringUtils::format("[%f,%f],",oneX,oneY);
            }

            //streamCnt.append("[").append(oneStreamCnt).append("],");
            streamCnt = oneStreamCnt;
        }

        std::string oneStreamCnt;
        for(const auto &oneVec:oneStroke) {
            float oneX = oneVec.x-TianHelper::offsetPos.x;
            float oneY = oneVec.y-TianHelper::offsetPos.y;

            oneStreamCnt += StringUtils::format("[%f,%f],",oneX,oneY);
        }

        streamCnt.append(oneStreamCnt);//.append("[").append().append("],");


        streamCnt += "]\r\n";
        SocketIOHelper::getInstant()->emit("write_stream", streamCnt);
        oneSIOWordPos.clear();
    }

    void initClassCeil(LayerColor *promptLayer,std::string title,float ceilY,int tag,float fontS)
    {
        Label* classListLab = Label::createWithTTF(title, "fonts/content.ttf", fontS);
        classListLab->setAnchorPoint(Vec2(0.5,0));
        classListLab->setPosition(Vec2(promptLayer->getContentSize().width/2, ceilY));//visibleSize.width*0.64, 0
        classListLab->setTag(tag);
        promptLayer->addChild(classListLab);
    }

    void initStorePageInfo() {
        std::string writablePath = FileUtils::getInstance()->getWritablePath();
        writablePath.append(CLASS_DATA_INFO_PATH);
        bool isExist = FileUtils::getInstance()->isFileExist(writablePath);
        if (isExist) {
            handPageInfo = FileUtils::getInstance()->getValueMapFromFile(writablePath);
        } else {
            writeInitPageInfo();
        }

        HandTianScene::classNum = handPageInfo["curClass"].asInt();
        HandTianScene::termNo   = handPageInfo["curTerm"].asInt();

        int pos = HandTianScene::classNum * 2;
        if (HandTianScene::termNo == 1) {
            pos--;
        }
        ValueMap hpiMap = handPageInfo[std::to_string(pos)].asValueMap();
        HandTianScene::pageNo = hpiMap["curPage"].asInt();
        if(HandTianScene::pageNo <= 0){
            HandTianScene::pageNo = 1;
        }
    }

    void writeInitPageInfo() {
        ValueMap pageInfo;
        pageInfo["curClass"] = Value(1);
        pageInfo["curTerm"] = Value(1);

        /*每年级有多少页面*/
        const static std::map<int, int> classPageMapping = {
                {12, 40},//6年级下半学期
                {11, 60},//6年级上半学期
                {10, 60},//5年级下半学期
                {9,  73},//5年级上半学期
                {8,  83},//4年级下半学期
                {7,  83},//4年级上半学期
                {6,  83},//3年级下半学期
                {5,  83},//3年级上半学期
                {4,  80},//2年级下半学期
                {3,  83},//2年级上半学期
                {2,  66},//1年级下半学期
                {1,  100} //1年级上半学期
        };

        for (const auto &onePageStat:classPageMapping) {
            ValueMap ppageStat;

            int number = 0;

            ppageStat["totalPage"] = Value(onePageStat.second);
            ppageStat["curPage"] = Value(number);
            ppageStat["writtenPage"] = Value(number);

            pageInfo[std::to_string(onePageStat.first)] = Value(ppageStat);
        }

        std::string writablePath = FileUtils::getInstance()->getWritablePath();
        std::string fullPath = writablePath + CLASS_DATA_INFO_PATH;
        if (FileUtils::getInstance()->writeValueMapToFile(pageInfo, fullPath.c_str())) {
            setNotifyLabel("初始页码存储完毕√");
            handPageInfo = pageInfo;
        } else {
            setNotifyLabel("初始页码存储失败×");
        }
    }

    /*红心赞赏*/
    Texture2D *reddiggTexture;

    /*评论*/
    SioPageStatInfo oneSioStatInfo;
    std::vector<SIOUserInfo> sioUserInfoVec;

    /*SIO 相关*/
    //cocos2d::network::SIOClient *sioClient;
    std::string SIOjoinRoom;
    std::string SIOQRMd5;
    std::atomic<bool> sioClientIsConnected;


    /*当前选择巴长度*/
    int selectedBarPos;
    /*当前选择班-列表位*/
    int selectedClassPageListBarPos;
    /*当前选择页*/
    int selectedClassPageBarPos;

    /*id -> 画映射*/
    std::map<std::string, DrawNode *> idMappingDrawNode;

    /*左侧大图*/
    //std::array<DrawNode *,3> pageWordsList;
    //std::array<Label *,3> pageWordsListLabel;

    /*对联左侧*/
    std::array<Label *,3> leftBanner;

    /*对联右侧*/
    std::array<Label *,3> rightBanner;

    /*对联底部*/
    std::array<Label *,3> bottomBanner;

    /*造句框*/
    std::array<Label *,3> generalInfoBanner;

    /*拼音框*/
    std::array<Label *,3> pinyinBar;

    /*分笔区*/
    std::array<LayerColor *,3> stepByStep;

    /*左侧动态笔画*/
    DrawNodeArr dynamicDrawTian;
    DrawNodeArrCourse dynamicDrawCourse;

    /*书写的几个区域*/
    std::array<DrawNodeArr,6> handDrawTian;

    /*下面的拼音*/
    std::array<LabelNodeArr, 3> wordsPinyin;

    /*下面的词组*/
    std::array<HandDrawNodeArr, 3> wordInWordList;

    float aCanvasSide;

    float dynamicCanvasSide;

    float lineWidth;

    std::array<int, 2> handDrawTianPos;

    bool isSingleanchor = false;//是否在矫正位置

    /*笔记*/
    std::vector<Vec2> oneStroke;
    std::vector<std::vector<Vec2>> oneWordPos;

    /*流化锁*/
    std::mutex SIOStreamMutex;
    std::vector<std::vector<Vec2>> oneSIOWordPos;

    /*打分的 node*/
    DrawNode* scoreDrawNode;

    CHOOSE_CLASS_PAGE curClassPageChooser ;

    //页面基础の信息汉那蛤
    ValueMap handPageInfo;

    /*每年级有多少页面*/
    std::map<int,int> classPageMapping = {
            {1,40},//6年级下半学期
            {2,60},//6年级上半学期
            {3,60},//5年级下半学期
            {4,73},//5年级上半学期
            {5,83},//4年级下半学期
            {6,83},//4年级上半学期
            {7,83},//3年级下半学期
            {8,83},//3年级上半学期
            {9,80},//2年级下半学期
            {10,83},//2年级上半学期
            {11,66},//1年级下半学期
            {12,100} //1年级上半学期
    };
//书の图汉位置
    std::array<std::string, 12> fileNameThumb = {"class_1_1_thumb.png", "class_1_2_thumb.png",
                                                 "class_2_1_thumb.png", "class_2_2_thumb.png",
                                                 "class_3_1_thumb.png", "class_3_2_thumb.png",
                                                 "class_4_1_thumb.png", "class_4_2_thumb.png",
                                                 "class_5_1_thumb.png", "class_5_2_thumb.png",
                                                 "class_6_1_thumb.png", "class_6_2_thumb.png"};

    bool isLogoutConfirm;
    TableView* commentTV;
    Vec2 commentTVSize;
    bool isTableLoadData = false;
    float tableLayerWidth;


    // implement the "static create()" method manually
    CREATE_FUNC(HandTianScene);
};

#endif //PROJ_ANDROID_HANDTIANSCENE